@odoo/o-spreadsheet 18.2.12 → 18.2.14
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 +46 -45
- package/dist/o-spreadsheet.esm.js +354 -243
- package/dist/o-spreadsheet.iife.js +354 -243
- package/dist/o-spreadsheet.iife.min.js +385 -385
- 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.2.
|
|
6
|
-
* @date 2025-05-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 18.2.14
|
|
6
|
+
* @date 2025-05-26T12:35:51.528Z
|
|
7
|
+
* @hash db90fca
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
'use strict';
|
|
@@ -1619,18 +1619,53 @@ function lettersToNumber(letters) {
|
|
|
1619
1619
|
let result = 0;
|
|
1620
1620
|
const l = letters.length;
|
|
1621
1621
|
for (let i = 0; i < l; i++) {
|
|
1622
|
-
const
|
|
1623
|
-
const colIndex = charCode >= 65 && charCode <= 90 ? charCode - 64 : charCode - 96;
|
|
1622
|
+
const colIndex = charToNumber(letters[i]);
|
|
1624
1623
|
result = result * 26 + colIndex;
|
|
1625
1624
|
}
|
|
1626
1625
|
return result - 1;
|
|
1627
1626
|
}
|
|
1627
|
+
function charToNumber(char) {
|
|
1628
|
+
const charCode = char.charCodeAt(0);
|
|
1629
|
+
return charCode >= 65 && charCode <= 90 ? charCode - 64 : charCode - 96;
|
|
1630
|
+
}
|
|
1628
1631
|
function isCharALetter(char) {
|
|
1629
1632
|
return (char >= "A" && char <= "Z") || (char >= "a" && char <= "z");
|
|
1630
1633
|
}
|
|
1631
1634
|
function isCharADigit(char) {
|
|
1632
1635
|
return char >= "0" && char <= "9";
|
|
1633
1636
|
}
|
|
1637
|
+
// we limit the max column to 3 letters and max row to 7 digits for performance reasons
|
|
1638
|
+
const MAX_COL = lettersToNumber("ZZZ");
|
|
1639
|
+
const MAX_ROW = 9999998;
|
|
1640
|
+
function consumeSpaces(chars) {
|
|
1641
|
+
while (chars.current === " ") {
|
|
1642
|
+
chars.advanceBy(1);
|
|
1643
|
+
}
|
|
1644
|
+
}
|
|
1645
|
+
function consumeLetters(chars) {
|
|
1646
|
+
if (chars.current === "$")
|
|
1647
|
+
chars.advanceBy(1);
|
|
1648
|
+
if (!chars.current || !isCharALetter(chars.current)) {
|
|
1649
|
+
return -1;
|
|
1650
|
+
}
|
|
1651
|
+
let colCoordinate = 0;
|
|
1652
|
+
while (chars.current && isCharALetter(chars.current)) {
|
|
1653
|
+
colCoordinate = colCoordinate * 26 + charToNumber(chars.shift());
|
|
1654
|
+
}
|
|
1655
|
+
return colCoordinate;
|
|
1656
|
+
}
|
|
1657
|
+
function consumeDigits(chars) {
|
|
1658
|
+
if (chars.current === "$")
|
|
1659
|
+
chars.advanceBy(1);
|
|
1660
|
+
if (!chars.current || !isCharADigit(chars.current)) {
|
|
1661
|
+
return -1;
|
|
1662
|
+
}
|
|
1663
|
+
let num = 0;
|
|
1664
|
+
while (chars.current && isCharADigit(chars.current)) {
|
|
1665
|
+
num = num * 10 + Number(chars.shift());
|
|
1666
|
+
}
|
|
1667
|
+
return num;
|
|
1668
|
+
}
|
|
1634
1669
|
/**
|
|
1635
1670
|
* Convert a "XC" coordinate to cartesian coordinates.
|
|
1636
1671
|
*
|
|
@@ -1641,33 +1676,17 @@ function isCharADigit(char) {
|
|
|
1641
1676
|
* Note: it also accepts lowercase coordinates, but not fixed references
|
|
1642
1677
|
*/
|
|
1643
1678
|
function toCartesian(xc) {
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
// Process letter part
|
|
1649
|
-
if (xc[i] === "$")
|
|
1650
|
-
i++;
|
|
1651
|
-
while (i < xc.length && isCharALetter(xc[i])) {
|
|
1652
|
-
letterPart += xc[i++];
|
|
1653
|
-
}
|
|
1654
|
-
if (letterPart.length === 0 || letterPart.length > 3) {
|
|
1655
|
-
// limit to max 3 letters for performance reasons
|
|
1679
|
+
const chars = new TokenizingChars(xc);
|
|
1680
|
+
consumeSpaces(chars);
|
|
1681
|
+
const letterPart = consumeLetters(chars);
|
|
1682
|
+
if (letterPart === -1 || !chars.current) {
|
|
1656
1683
|
throw new Error(`Invalid cell description: ${xc}`);
|
|
1657
1684
|
}
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
}
|
|
1664
|
-
if (i !== xc.length || numberPart.length === 0 || numberPart.length > 7) {
|
|
1665
|
-
// limit to max 7 numbers for performance reasons
|
|
1666
|
-
throw new Error(`Invalid cell description: ${xc}`);
|
|
1667
|
-
}
|
|
1668
|
-
const col = lettersToNumber(letterPart);
|
|
1669
|
-
const row = Number(numberPart) - 1;
|
|
1670
|
-
if (isNaN(row)) {
|
|
1685
|
+
const num = consumeDigits(chars);
|
|
1686
|
+
consumeSpaces(chars);
|
|
1687
|
+
const col = letterPart - 1;
|
|
1688
|
+
const row = num - 1;
|
|
1689
|
+
if (!chars.isOver() || col > MAX_COL || row > MAX_ROW) {
|
|
1671
1690
|
throw new Error(`Invalid cell description: ${xc}`);
|
|
1672
1691
|
}
|
|
1673
1692
|
return { col, row };
|
|
@@ -2079,67 +2098,6 @@ class LazyTranslatedString extends String {
|
|
|
2079
2098
|
}
|
|
2080
2099
|
}
|
|
2081
2100
|
|
|
2082
|
-
/** Reference of a cell (eg. A1, $B$5) */
|
|
2083
|
-
const cellReference = new RegExp(/\$?([A-Z]{1,3})\$?([0-9]{1,7})/, "i");
|
|
2084
|
-
// Same as above, but matches the exact string (nothing before or after)
|
|
2085
|
-
const singleCellReference = new RegExp(/^\$?([A-Z]{1,3})\$?([0-9]{1,7})$/, "i");
|
|
2086
|
-
/** Reference of a column header (eg. A, AB, $A) */
|
|
2087
|
-
const colHeader = new RegExp(/^\$?([A-Z]{1,3})+$/, "i");
|
|
2088
|
-
/** Reference of a row header (eg. 1, $1) */
|
|
2089
|
-
const rowHeader = new RegExp(/^\$?([0-9]{1,7})+$/, "i");
|
|
2090
|
-
/** Reference of a column (eg. A, $CA, Sheet1!B) */
|
|
2091
|
-
const colReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([A-Z]{1,3})$/, "i");
|
|
2092
|
-
/** Reference of a row (eg. 1, 59, Sheet1!9) */
|
|
2093
|
-
const rowReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([0-9]{1,7})$/, "i");
|
|
2094
|
-
/** Reference of a normal range or a full row range (eg. A1:B1, 1:$5, $A2:5) */
|
|
2095
|
-
const fullRowXc = /(\$?[A-Z]{1,3})?\$?[0-9]{1,7}\s*:\s*(\$?[A-Z]{1,3})?\$?[0-9]{1,7}\s*/i;
|
|
2096
|
-
/** Reference of a normal range or a column row range (eg. A1:B1, A:$B, $A1:C) */
|
|
2097
|
-
const fullColXc = /\$?[A-Z]{1,3}(\$?[0-9]{1,7})?\s*:\s*\$?[A-Z]{1,3}(\$?[0-9]{1,7})?\s*/i;
|
|
2098
|
-
/** Reference of a cell or a range, it can be a bounded range, a full row or a full column */
|
|
2099
|
-
const rangeReference = new RegExp(/^\s*('.+'!|[^']+!)?/.source +
|
|
2100
|
-
"(" +
|
|
2101
|
-
[cellReference.source, fullRowXc.source, fullColXc.source].join("|") +
|
|
2102
|
-
")" +
|
|
2103
|
-
/$/.source, "i");
|
|
2104
|
-
/**
|
|
2105
|
-
* Return true if the given xc is the reference of a column (e.g. A or AC or Sheet1!A)
|
|
2106
|
-
*/
|
|
2107
|
-
function isColReference(xc) {
|
|
2108
|
-
return colReference.test(xc);
|
|
2109
|
-
}
|
|
2110
|
-
/**
|
|
2111
|
-
* Return true if the given xc is the reference of a column (e.g. 1 or Sheet1!1)
|
|
2112
|
-
*/
|
|
2113
|
-
function isRowReference(xc) {
|
|
2114
|
-
return rowReference.test(xc);
|
|
2115
|
-
}
|
|
2116
|
-
function isColHeader(str) {
|
|
2117
|
-
return colHeader.test(str);
|
|
2118
|
-
}
|
|
2119
|
-
function isRowHeader(str) {
|
|
2120
|
-
return rowHeader.test(str);
|
|
2121
|
-
}
|
|
2122
|
-
/**
|
|
2123
|
-
* Return true if the given xc is the reference of a single cell,
|
|
2124
|
-
* without any specified sheet (e.g. A1)
|
|
2125
|
-
*/
|
|
2126
|
-
function isSingleCellReference(xc) {
|
|
2127
|
-
return singleCellReference.test(xc);
|
|
2128
|
-
}
|
|
2129
|
-
function splitReference(ref) {
|
|
2130
|
-
if (!ref.includes("!")) {
|
|
2131
|
-
return { xc: ref };
|
|
2132
|
-
}
|
|
2133
|
-
const parts = ref.split("!");
|
|
2134
|
-
const xc = parts.pop();
|
|
2135
|
-
const sheetName = getUnquotedSheetName(parts.join("!")) || undefined;
|
|
2136
|
-
return { sheetName, xc };
|
|
2137
|
-
}
|
|
2138
|
-
/** Return a reference SheetName!xc from the given arguments */
|
|
2139
|
-
function getFullReference(sheetName, xc) {
|
|
2140
|
-
return sheetName !== undefined ? `${getCanonicalSymbolName(sheetName)}!${xc}` : xc;
|
|
2141
|
-
}
|
|
2142
|
-
|
|
2143
2101
|
/**
|
|
2144
2102
|
* Convert from a cartesian reference to a Zone
|
|
2145
2103
|
* The range boundaries will be kept in the same order as the
|
|
@@ -2157,63 +2115,55 @@ function getFullReference(sheetName, xc) {
|
|
|
2157
2115
|
*
|
|
2158
2116
|
*/
|
|
2159
2117
|
function toZoneWithoutBoundaryChanges(xc) {
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
if (
|
|
2164
|
-
|
|
2165
|
-
}
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
if (xc.includes(":")) {
|
|
2169
|
-
[firstRangePart, secondRangePart] = xc.split(":");
|
|
2170
|
-
firstRangePart = firstRangePart.trim();
|
|
2171
|
-
secondRangePart = secondRangePart.trim();
|
|
2172
|
-
}
|
|
2173
|
-
else {
|
|
2174
|
-
firstRangePart = xc.trim();
|
|
2175
|
-
}
|
|
2118
|
+
const chars = new TokenizingChars(xc);
|
|
2119
|
+
consumeSpaces(chars);
|
|
2120
|
+
const sheetSeparatorIndex = xc.indexOf("!");
|
|
2121
|
+
if (sheetSeparatorIndex !== -1) {
|
|
2122
|
+
chars.advanceBy(sheetSeparatorIndex + 1);
|
|
2123
|
+
}
|
|
2124
|
+
const leftLetters = consumeLetters(chars);
|
|
2125
|
+
const leftNumbers = consumeDigits(chars);
|
|
2176
2126
|
let top, bottom, left, right;
|
|
2177
2127
|
let fullCol = false;
|
|
2178
2128
|
let fullRow = false;
|
|
2179
2129
|
let hasHeader = false;
|
|
2180
|
-
if (
|
|
2181
|
-
left = right =
|
|
2130
|
+
if (leftNumbers === -1) {
|
|
2131
|
+
left = right = leftLetters - 1;
|
|
2182
2132
|
top = bottom = 0;
|
|
2183
2133
|
fullCol = true;
|
|
2184
2134
|
}
|
|
2185
|
-
else if (
|
|
2186
|
-
top = bottom =
|
|
2135
|
+
else if (leftLetters === -1) {
|
|
2136
|
+
top = bottom = leftNumbers - 1;
|
|
2187
2137
|
left = right = 0;
|
|
2188
2138
|
fullRow = true;
|
|
2189
2139
|
}
|
|
2190
2140
|
else {
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
top = bottom = c.row;
|
|
2141
|
+
left = right = leftLetters - 1;
|
|
2142
|
+
top = bottom = leftNumbers - 1;
|
|
2194
2143
|
hasHeader = true;
|
|
2195
2144
|
}
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2145
|
+
consumeSpaces(chars);
|
|
2146
|
+
if (chars.current === ":") {
|
|
2147
|
+
chars.advanceBy(1);
|
|
2148
|
+
consumeSpaces(chars);
|
|
2149
|
+
const rightLetters = consumeLetters(chars);
|
|
2150
|
+
const rightNumbers = consumeDigits(chars);
|
|
2151
|
+
if (rightNumbers === -1) {
|
|
2152
|
+
right = rightLetters - 1;
|
|
2199
2153
|
fullCol = true;
|
|
2200
2154
|
}
|
|
2201
|
-
else if (
|
|
2202
|
-
bottom =
|
|
2155
|
+
else if (rightLetters === -1) {
|
|
2156
|
+
bottom = rightNumbers - 1;
|
|
2203
2157
|
fullRow = true;
|
|
2204
2158
|
}
|
|
2205
2159
|
else {
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
bottom = c.row;
|
|
2160
|
+
right = rightLetters - 1;
|
|
2161
|
+
bottom = rightNumbers - 1;
|
|
2209
2162
|
top = fullCol ? bottom : top;
|
|
2210
2163
|
left = fullRow ? right : left;
|
|
2211
2164
|
hasHeader = true;
|
|
2212
2165
|
}
|
|
2213
2166
|
}
|
|
2214
|
-
if (fullCol && fullRow) {
|
|
2215
|
-
throw new Error("Wrong zone xc. The zone cannot be at the same time a full column and a full row");
|
|
2216
|
-
}
|
|
2217
2167
|
const zone = {
|
|
2218
2168
|
top,
|
|
2219
2169
|
left,
|
|
@@ -2242,7 +2192,16 @@ function toZoneWithoutBoundaryChanges(xc) {
|
|
|
2242
2192
|
*/
|
|
2243
2193
|
function toUnboundedZone(xc) {
|
|
2244
2194
|
const zone = toZoneWithoutBoundaryChanges(xc);
|
|
2245
|
-
|
|
2195
|
+
const orderedZone = reorderZone(zone);
|
|
2196
|
+
const bottom = orderedZone.bottom;
|
|
2197
|
+
const right = orderedZone.right;
|
|
2198
|
+
if ((bottom !== undefined && bottom > MAX_ROW) || (right !== undefined && right > MAX_COL)) {
|
|
2199
|
+
throw new Error(`Range string out of bounds: ${xc}`); // limit the size of the zone for performance
|
|
2200
|
+
}
|
|
2201
|
+
if (bottom === undefined && right === undefined) {
|
|
2202
|
+
throw new Error("Wrong zone xc. The zone cannot be at the same time a full column and a full row");
|
|
2203
|
+
}
|
|
2204
|
+
return orderedZone;
|
|
2246
2205
|
}
|
|
2247
2206
|
/**
|
|
2248
2207
|
* Convert from a cartesian reference to a Zone.
|
|
@@ -4192,6 +4151,113 @@ function transposeMatrix(matrix) {
|
|
|
4192
4151
|
}
|
|
4193
4152
|
return generateMatrix(matrix[0].length, matrix.length, (i, j) => matrix[j][i]);
|
|
4194
4153
|
}
|
|
4154
|
+
/**
|
|
4155
|
+
* Enables a formula function to accept matrix or vector inputs instead of simple value, computing results across multiple dimensions.
|
|
4156
|
+
*
|
|
4157
|
+
* ```
|
|
4158
|
+
* / |‾ ‾| \ |‾ ‾|
|
|
4159
|
+
* | | [A] | | | compute(A, D, E), compute(A, D, F), compute(A, D, G) |
|
|
4160
|
+
* applyVectorization| compute, | [B], D, [E, F, G] | | <=> | compute(B, D, E), compute(B, D, F), compute(B, D, G) |
|
|
4161
|
+
* | | [C] | | | compute(C, D, E), compute(C, D, F), compute(C, D, G) |
|
|
4162
|
+
* \ |_ _| / |_ _|
|
|
4163
|
+
* ```
|
|
4164
|
+
*
|
|
4165
|
+
* By default, all arguments are vectorized. To control which arguments are vectorized,
|
|
4166
|
+
* pass an `acceptToVectorize` boolean array of the same length as `args`:
|
|
4167
|
+
* - `true` enables vectorization for that argument
|
|
4168
|
+
* - `false` disables vectorization for that argument
|
|
4169
|
+
*
|
|
4170
|
+
* For example, with `[true, true, false]` on previous example you get:
|
|
4171
|
+
*
|
|
4172
|
+
* ```
|
|
4173
|
+
* |‾ ‾|
|
|
4174
|
+
* | compute(A, D, [E, F, G]) |
|
|
4175
|
+
* | compute(B, D, [E, F, G]) |
|
|
4176
|
+
* | compute(C, D, [E, F, G]) |
|
|
4177
|
+
* |_ _|
|
|
4178
|
+
* ```
|
|
4179
|
+
*
|
|
4180
|
+
* @remarks
|
|
4181
|
+
* This helper is automatically applied (by default) to **all** `compute` functions
|
|
4182
|
+
* across the various spreadsheet formula modules:
|
|
4183
|
+
* - If an argument is declared **scalar** (not `"range"`), it is vectorized.
|
|
4184
|
+
* - If **all** arguments are declared **ranges**, no vectorization occurs.
|
|
4185
|
+
* - e.g. `SUM(A1:B2)` returns a 1×1 sum over the range.
|
|
4186
|
+
* - e.g. `COS(A1:B2)` over `A1:B2` returns a 2×2 element-wise result.
|
|
4187
|
+
* - For special behaviors (e.g. the `IF` function), you may declare all arguments
|
|
4188
|
+
* as ranges and invoke this helper directly within your `compute` implementation.
|
|
4189
|
+
*/
|
|
4190
|
+
function applyVectorization(formula, args, acceptToVectorize = undefined) {
|
|
4191
|
+
let countVectorizedCol = 1;
|
|
4192
|
+
let countVectorizedRow = 1;
|
|
4193
|
+
let vectorizedColLimit = Infinity;
|
|
4194
|
+
let vectorizedRowLimit = Infinity;
|
|
4195
|
+
let vectorArgsType = undefined;
|
|
4196
|
+
for (let i = 0; i < args.length; i++) {
|
|
4197
|
+
const arg = args[i];
|
|
4198
|
+
if (isMatrix(arg) && (acceptToVectorize === undefined || acceptToVectorize[i])) {
|
|
4199
|
+
const nColumns = arg.length;
|
|
4200
|
+
const nRows = arg[0].length;
|
|
4201
|
+
if (nColumns !== 1 || nRows !== 1) {
|
|
4202
|
+
vectorArgsType ??= new Array(args.length);
|
|
4203
|
+
if (nColumns !== 1 && nRows !== 1) {
|
|
4204
|
+
vectorArgsType[i] = "matrix";
|
|
4205
|
+
countVectorizedCol = Math.max(countVectorizedCol, nColumns);
|
|
4206
|
+
countVectorizedRow = Math.max(countVectorizedRow, nRows);
|
|
4207
|
+
vectorizedColLimit = Math.min(vectorizedColLimit, nColumns);
|
|
4208
|
+
vectorizedRowLimit = Math.min(vectorizedRowLimit, nRows);
|
|
4209
|
+
}
|
|
4210
|
+
else if (nColumns !== 1) {
|
|
4211
|
+
vectorArgsType[i] = "horizontal";
|
|
4212
|
+
countVectorizedCol = Math.max(countVectorizedCol, nColumns);
|
|
4213
|
+
vectorizedColLimit = Math.min(vectorizedColLimit, nColumns);
|
|
4214
|
+
}
|
|
4215
|
+
else if (nRows !== 1) {
|
|
4216
|
+
vectorArgsType[i] = "vertical";
|
|
4217
|
+
countVectorizedRow = Math.max(countVectorizedRow, nRows);
|
|
4218
|
+
vectorizedRowLimit = Math.min(vectorizedRowLimit, nRows);
|
|
4219
|
+
}
|
|
4220
|
+
}
|
|
4221
|
+
else {
|
|
4222
|
+
args[i] = arg[0][0];
|
|
4223
|
+
}
|
|
4224
|
+
}
|
|
4225
|
+
}
|
|
4226
|
+
if (countVectorizedCol === 1 && countVectorizedRow === 1) {
|
|
4227
|
+
// either this function is not vectorized or it ends up with a 1x1 dimension
|
|
4228
|
+
return formula(...args);
|
|
4229
|
+
}
|
|
4230
|
+
const getArgOffset = (i, j) => args.map((arg, index) => {
|
|
4231
|
+
switch (vectorArgsType?.[index]) {
|
|
4232
|
+
case "matrix":
|
|
4233
|
+
return arg[i][j];
|
|
4234
|
+
case "horizontal":
|
|
4235
|
+
return arg[i][0];
|
|
4236
|
+
case "vertical":
|
|
4237
|
+
return arg[0][j];
|
|
4238
|
+
case undefined:
|
|
4239
|
+
return arg;
|
|
4240
|
+
}
|
|
4241
|
+
});
|
|
4242
|
+
return generateMatrix(countVectorizedCol, countVectorizedRow, (col, row) => {
|
|
4243
|
+
if (col > vectorizedColLimit - 1 || row > vectorizedRowLimit - 1) {
|
|
4244
|
+
return new NotAvailableError(_t("Array arguments to [[FUNCTION_NAME]] are of different size."));
|
|
4245
|
+
}
|
|
4246
|
+
const singleCellComputeResult = formula(...getArgOffset(col, row));
|
|
4247
|
+
// In the case where the user tries to vectorize arguments of an array formula, we will get an
|
|
4248
|
+
// array for every combination of the vectorized arguments, which will lead to a 3D matrix and
|
|
4249
|
+
// we won't be able to return the values.
|
|
4250
|
+
// In this case, we keep the first element of each spreading part, just as Excel does, and
|
|
4251
|
+
// create an array with these parts.
|
|
4252
|
+
// For exemple, we have MUNIT(x) that return an unitary matrix of x*x. If we use it with a
|
|
4253
|
+
// range, like MUNIT(A1:A2), we will get two unitary matrices (one for the value in A1 and one
|
|
4254
|
+
// for the value in A2). In this case, we will simply take the first value of each matrix and
|
|
4255
|
+
// return the array [First value of MUNIT(A1), First value of MUNIT(A2)].
|
|
4256
|
+
return isMatrix(singleCellComputeResult)
|
|
4257
|
+
? singleCellComputeResult[0][0]
|
|
4258
|
+
: singleCellComputeResult;
|
|
4259
|
+
});
|
|
4260
|
+
}
|
|
4195
4261
|
// -----------------------------------------------------------------------------
|
|
4196
4262
|
// CONDITIONAL EXPLORE FUNCTIONS
|
|
4197
4263
|
// -----------------------------------------------------------------------------
|
|
@@ -5976,6 +6042,67 @@ function scrollDelay(value) {
|
|
|
5976
6042
|
return MIN_DELAY + (MAX_DELAY - MIN_DELAY) * Math.exp(-ACCELERATION * (value - 1));
|
|
5977
6043
|
}
|
|
5978
6044
|
|
|
6045
|
+
/** Reference of a cell (eg. A1, $B$5) */
|
|
6046
|
+
const cellReference = new RegExp(/\$?([A-Z]{1,3})\$?([0-9]{1,7})/, "i");
|
|
6047
|
+
// Same as above, but matches the exact string (nothing before or after)
|
|
6048
|
+
const singleCellReference = new RegExp(/^\$?([A-Z]{1,3})\$?([0-9]{1,7})$/, "i");
|
|
6049
|
+
/** Reference of a column header (eg. A, AB, $A) */
|
|
6050
|
+
const colHeader = new RegExp(/^\$?([A-Z]{1,3})+$/, "i");
|
|
6051
|
+
/** Reference of a row header (eg. 1, $1) */
|
|
6052
|
+
const rowHeader = new RegExp(/^\$?([0-9]{1,7})+$/, "i");
|
|
6053
|
+
/** Reference of a column (eg. A, $CA, Sheet1!B) */
|
|
6054
|
+
const colReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([A-Z]{1,3})$/, "i");
|
|
6055
|
+
/** Reference of a row (eg. 1, 59, Sheet1!9) */
|
|
6056
|
+
const rowReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([0-9]{1,7})$/, "i");
|
|
6057
|
+
/** Reference of a normal range or a full row range (eg. A1:B1, 1:$5, $A2:5) */
|
|
6058
|
+
const fullRowXc = /(\$?[A-Z]{1,3})?\$?[0-9]{1,7}\s*:\s*(\$?[A-Z]{1,3})?\$?[0-9]{1,7}\s*/i;
|
|
6059
|
+
/** Reference of a normal range or a column row range (eg. A1:B1, A:$B, $A1:C) */
|
|
6060
|
+
const fullColXc = /\$?[A-Z]{1,3}(\$?[0-9]{1,7})?\s*:\s*\$?[A-Z]{1,3}(\$?[0-9]{1,7})?\s*/i;
|
|
6061
|
+
/** Reference of a cell or a range, it can be a bounded range, a full row or a full column */
|
|
6062
|
+
const rangeReference = new RegExp(/^\s*('.+'!|[^']+!)?/.source +
|
|
6063
|
+
"(" +
|
|
6064
|
+
[cellReference.source, fullRowXc.source, fullColXc.source].join("|") +
|
|
6065
|
+
")" +
|
|
6066
|
+
/$/.source, "i");
|
|
6067
|
+
/**
|
|
6068
|
+
* Return true if the given xc is the reference of a column (e.g. A or AC or Sheet1!A)
|
|
6069
|
+
*/
|
|
6070
|
+
function isColReference(xc) {
|
|
6071
|
+
return colReference.test(xc);
|
|
6072
|
+
}
|
|
6073
|
+
/**
|
|
6074
|
+
* Return true if the given xc is the reference of a column (e.g. 1 or Sheet1!1)
|
|
6075
|
+
*/
|
|
6076
|
+
function isRowReference(xc) {
|
|
6077
|
+
return rowReference.test(xc);
|
|
6078
|
+
}
|
|
6079
|
+
function isColHeader(str) {
|
|
6080
|
+
return colHeader.test(str);
|
|
6081
|
+
}
|
|
6082
|
+
function isRowHeader(str) {
|
|
6083
|
+
return rowHeader.test(str);
|
|
6084
|
+
}
|
|
6085
|
+
/**
|
|
6086
|
+
* Return true if the given xc is the reference of a single cell,
|
|
6087
|
+
* without any specified sheet (e.g. A1)
|
|
6088
|
+
*/
|
|
6089
|
+
function isSingleCellReference(xc) {
|
|
6090
|
+
return singleCellReference.test(xc);
|
|
6091
|
+
}
|
|
6092
|
+
function splitReference(ref) {
|
|
6093
|
+
if (!ref.includes("!")) {
|
|
6094
|
+
return { xc: ref };
|
|
6095
|
+
}
|
|
6096
|
+
const parts = ref.split("!");
|
|
6097
|
+
const xc = parts.pop();
|
|
6098
|
+
const sheetName = getUnquotedSheetName(parts.join("!")) || undefined;
|
|
6099
|
+
return { sheetName, xc };
|
|
6100
|
+
}
|
|
6101
|
+
/** Return a reference SheetName!xc from the given arguments */
|
|
6102
|
+
function getFullReference(sheetName, xc) {
|
|
6103
|
+
return sheetName !== undefined ? `${getCanonicalSymbolName(sheetName)}!${xc}` : xc;
|
|
6104
|
+
}
|
|
6105
|
+
|
|
5979
6106
|
class RangeImpl {
|
|
5980
6107
|
getSheetSize;
|
|
5981
6108
|
_zone;
|
|
@@ -7422,14 +7549,20 @@ function multiplyMatrices(matrix1, matrix2) {
|
|
|
7422
7549
|
/**
|
|
7423
7550
|
* Return the input if it's a scalar or the first element of the input if it's a matrix.
|
|
7424
7551
|
*/
|
|
7425
|
-
function toScalar(
|
|
7426
|
-
if (!isMatrix(
|
|
7427
|
-
return
|
|
7552
|
+
function toScalar(arg) {
|
|
7553
|
+
if (!isMatrix(arg)) {
|
|
7554
|
+
return arg;
|
|
7428
7555
|
}
|
|
7429
|
-
if (
|
|
7556
|
+
if (!isSingleElementMatrix(arg)) {
|
|
7430
7557
|
throw new EvaluationError(_t("The value should be a scalar or a 1x1 matrix"));
|
|
7431
7558
|
}
|
|
7432
|
-
return
|
|
7559
|
+
return arg[0][0];
|
|
7560
|
+
}
|
|
7561
|
+
function isSingleElementMatrix(matrix) {
|
|
7562
|
+
return matrix.length === 1 && matrix[0].length === 1;
|
|
7563
|
+
}
|
|
7564
|
+
function isMultipleElementMatrix(arg) {
|
|
7565
|
+
return isMatrix(arg) && !isSingleElementMatrix(arg);
|
|
7433
7566
|
}
|
|
7434
7567
|
|
|
7435
7568
|
function assertSameNumberOfElements(...args) {
|
|
@@ -15437,7 +15570,7 @@ const FILTER = {
|
|
|
15437
15570
|
}
|
|
15438
15571
|
return mode === "row" ? transposeMatrix(result) : result;
|
|
15439
15572
|
},
|
|
15440
|
-
isExported:
|
|
15573
|
+
isExported: false,
|
|
15441
15574
|
};
|
|
15442
15575
|
// -----------------------------------------------------------------------------
|
|
15443
15576
|
// SORT
|
|
@@ -18568,16 +18701,23 @@ const FALSE = {
|
|
|
18568
18701
|
const IF = {
|
|
18569
18702
|
description: _t("Returns value depending on logical expression."),
|
|
18570
18703
|
args: [
|
|
18571
|
-
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.")),
|
|
18572
|
-
arg("value_if_true (any)", _t("The value the function returns if logical_expression is TRUE.")),
|
|
18573
|
-
arg("value_if_false (any, default=FALSE)", _t("The value the function returns if logical_expression is FALSE.")),
|
|
18704
|
+
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.")),
|
|
18705
|
+
arg("value_if_true (any, range)", _t("The value the function returns if logical_expression is TRUE.")),
|
|
18706
|
+
arg("value_if_false (any, range, default=FALSE)", _t("The value the function returns if logical_expression is FALSE.")),
|
|
18574
18707
|
],
|
|
18575
18708
|
compute: function (logicalExpression, valueIfTrue, valueIfFalse) {
|
|
18576
|
-
|
|
18709
|
+
if (isMultipleElementMatrix(logicalExpression)) {
|
|
18710
|
+
return applyVectorization(IF.compute, [logicalExpression, valueIfTrue, valueIfFalse]);
|
|
18711
|
+
}
|
|
18712
|
+
let result = toBoolean(toScalar(logicalExpression)) ? valueIfTrue : valueIfFalse;
|
|
18713
|
+
// useful for interpreting empty cell references as empty strings. But must be removed to make empty cell references equal to zero
|
|
18714
|
+
if (!isMultipleElementMatrix(result)) {
|
|
18715
|
+
result = toScalar(result);
|
|
18716
|
+
}
|
|
18577
18717
|
if (result === undefined) {
|
|
18578
18718
|
return { value: "" };
|
|
18579
18719
|
}
|
|
18580
|
-
if (result.value === null) {
|
|
18720
|
+
if (!isMatrix(result) && result.value === null) {
|
|
18581
18721
|
return { ...result, value: "" };
|
|
18582
18722
|
}
|
|
18583
18723
|
return result;
|
|
@@ -18590,15 +18730,22 @@ const IF = {
|
|
|
18590
18730
|
const IFERROR = {
|
|
18591
18731
|
description: _t("Value if it is not an error, otherwise 2nd argument."),
|
|
18592
18732
|
args: [
|
|
18593
|
-
arg("value (any)", _t("The value to return if value itself is not an error.")),
|
|
18594
|
-
arg(`value_if_error (any, default="empty")`, _t("The value the function returns if value is an error.")),
|
|
18733
|
+
arg("value (any, range)", _t("The value to return if value itself is not an error.")),
|
|
18734
|
+
arg(`value_if_error (any, range, default="empty")`, _t("The value the function returns if value is an error.")),
|
|
18595
18735
|
],
|
|
18596
|
-
compute: function (value, valueIfError
|
|
18597
|
-
|
|
18736
|
+
compute: function (value, valueIfError) {
|
|
18737
|
+
if (isMultipleElementMatrix(value)) {
|
|
18738
|
+
return applyVectorization(IFERROR.compute, [value, valueIfError]);
|
|
18739
|
+
}
|
|
18740
|
+
let result = isEvaluationError(toScalar(value)?.value) ? valueIfError : value;
|
|
18741
|
+
// useful for interpreting empty cell references as empty strings. But must be removed to make empty cell references equal to zero
|
|
18742
|
+
if (!isMultipleElementMatrix(result)) {
|
|
18743
|
+
result = toScalar(result);
|
|
18744
|
+
}
|
|
18598
18745
|
if (result === undefined) {
|
|
18599
18746
|
return { value: "" };
|
|
18600
18747
|
}
|
|
18601
|
-
if (result.value === null) {
|
|
18748
|
+
if (!isMatrix(result) && result.value === null) {
|
|
18602
18749
|
return { ...result, value: "" };
|
|
18603
18750
|
}
|
|
18604
18751
|
return result;
|
|
@@ -18611,15 +18758,22 @@ const IFERROR = {
|
|
|
18611
18758
|
const IFNA = {
|
|
18612
18759
|
description: _t("Value if it is not an #N/A error, otherwise 2nd argument."),
|
|
18613
18760
|
args: [
|
|
18614
|
-
arg("value (any)", _t("The value to return if value itself is not #N/A an error.")),
|
|
18615
|
-
arg(`value_if_error (any, default="empty")`, _t("The value the function returns if value is an #N/A error.")),
|
|
18761
|
+
arg("value (any, range)", _t("The value to return if value itself is not #N/A an error.")),
|
|
18762
|
+
arg(`value_if_error (any, range, default="empty")`, _t("The value the function returns if value is an #N/A error.")),
|
|
18616
18763
|
],
|
|
18617
|
-
compute: function (value, valueIfError
|
|
18618
|
-
|
|
18764
|
+
compute: function (value, valueIfError) {
|
|
18765
|
+
if (isMultipleElementMatrix(value)) {
|
|
18766
|
+
return applyVectorization(IFNA.compute, [value, valueIfError]);
|
|
18767
|
+
}
|
|
18768
|
+
let result = toScalar(value)?.value === CellErrorType.NotAvailable ? valueIfError : value;
|
|
18769
|
+
// useful for interpreting empty cell references as empty strings. But must be removed to make empty cell references equal to zero
|
|
18770
|
+
if (!isMultipleElementMatrix(result)) {
|
|
18771
|
+
result = toScalar(result);
|
|
18772
|
+
}
|
|
18619
18773
|
if (result === undefined) {
|
|
18620
18774
|
return { value: "" };
|
|
18621
18775
|
}
|
|
18622
|
-
if (result.value === null) {
|
|
18776
|
+
if (!isMatrix(result) && result.value === null) {
|
|
18623
18777
|
return { ...result, value: "" };
|
|
18624
18778
|
}
|
|
18625
18779
|
return result;
|
|
@@ -18632,23 +18786,31 @@ const IFNA = {
|
|
|
18632
18786
|
const IFS = {
|
|
18633
18787
|
description: _t("Returns a value depending on multiple logical expressions."),
|
|
18634
18788
|
args: [
|
|
18635
|
-
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.")),
|
|
18636
|
-
arg("value1 (any)", _t("The returned value if condition1 is TRUE.")),
|
|
18637
|
-
arg("condition2 (boolean, any, repeating)", _t("Additional conditions to be evaluated if the previous ones are FALSE.")),
|
|
18638
|
-
arg("value2 (any, repeating)", _t("Additional values to be returned if their corresponding conditions are TRUE.")),
|
|
18789
|
+
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.")),
|
|
18790
|
+
arg("value1 (any, range)", _t("The returned value if condition1 is TRUE.")),
|
|
18791
|
+
arg("condition2 (boolean, any, range, repeating)", _t("Additional conditions to be evaluated if the previous ones are FALSE.")),
|
|
18792
|
+
arg("value2 (any, range, repeating)", _t("Additional values to be returned if their corresponding conditions are TRUE.")),
|
|
18639
18793
|
],
|
|
18640
18794
|
compute: function (...values) {
|
|
18641
18795
|
assert(() => values.length % 2 === 0, _t("Wrong number of arguments. Expected an even number of arguments."));
|
|
18642
|
-
|
|
18643
|
-
if (
|
|
18644
|
-
|
|
18645
|
-
|
|
18796
|
+
while (values.length > 0) {
|
|
18797
|
+
if (isMultipleElementMatrix(values[0])) {
|
|
18798
|
+
return applyVectorization(IFS.compute, values);
|
|
18799
|
+
}
|
|
18800
|
+
const condition = toBoolean(toScalar(values.shift()));
|
|
18801
|
+
let valueIfTrue = values.shift();
|
|
18802
|
+
if (condition) {
|
|
18803
|
+
// useful for interpreting empty cell references as empty strings. But must be removed to make empty cell references equal to zero
|
|
18804
|
+
if (!isMultipleElementMatrix(valueIfTrue)) {
|
|
18805
|
+
valueIfTrue = toScalar(valueIfTrue);
|
|
18806
|
+
}
|
|
18807
|
+
if (valueIfTrue === undefined) {
|
|
18646
18808
|
return { value: "" };
|
|
18647
18809
|
}
|
|
18648
|
-
if (
|
|
18649
|
-
return { ...
|
|
18810
|
+
if (!isMatrix(valueIfTrue) && valueIfTrue.value === null) {
|
|
18811
|
+
return { ...valueIfTrue, value: "" };
|
|
18650
18812
|
}
|
|
18651
|
-
return
|
|
18813
|
+
return valueIfTrue;
|
|
18652
18814
|
}
|
|
18653
18815
|
}
|
|
18654
18816
|
return new EvaluationError(_t("No match."));
|
|
@@ -20310,7 +20472,7 @@ const SPLIT = {
|
|
|
20310
20472
|
}
|
|
20311
20473
|
return transposeMatrix([result]);
|
|
20312
20474
|
},
|
|
20313
|
-
isExported:
|
|
20475
|
+
isExported: false,
|
|
20314
20476
|
};
|
|
20315
20477
|
// -----------------------------------------------------------------------------
|
|
20316
20478
|
// SUBSTITUTE
|
|
@@ -20503,86 +20665,21 @@ for (let category of categories) {
|
|
|
20503
20665
|
functionRegistry.add(name, { isExported: false, ...addDescr });
|
|
20504
20666
|
}
|
|
20505
20667
|
}
|
|
20506
|
-
|
|
20668
|
+
//------------------------------------------------------------------------------
|
|
20669
|
+
// CREATE COMPUTE FUNCTION
|
|
20670
|
+
//------------------------------------------------------------------------------
|
|
20507
20671
|
function createComputeFunction(descr, functionName) {
|
|
20508
20672
|
function vectorizedCompute(...args) {
|
|
20509
|
-
|
|
20510
|
-
let countVectorizableRow = 1;
|
|
20511
|
-
let vectorizableColLimit = Infinity;
|
|
20512
|
-
let vectorizableRowLimit = Infinity;
|
|
20513
|
-
let vectorArgsType = undefined;
|
|
20514
|
-
//#region Compute vectorisation limits
|
|
20673
|
+
const acceptToVectorize = [];
|
|
20515
20674
|
for (let i = 0; i < args.length; i++) {
|
|
20516
20675
|
const argDefinition = descr.args[descr.getArgToFocus(i + 1) - 1];
|
|
20517
20676
|
const arg = args[i];
|
|
20518
|
-
if (isMatrix(arg) && !argDefinition.acceptMatrix) {
|
|
20519
|
-
// if argDefinition does not accept a matrix but arg is still a matrix
|
|
20520
|
-
// --> triggers the arguments vectorization
|
|
20521
|
-
const nColumns = arg.length;
|
|
20522
|
-
const nRows = arg[0].length;
|
|
20523
|
-
if (nColumns !== 1 || nRows !== 1) {
|
|
20524
|
-
vectorArgsType ??= new Array(args.length);
|
|
20525
|
-
if (nColumns !== 1 && nRows !== 1) {
|
|
20526
|
-
vectorArgsType[i] = "matrix";
|
|
20527
|
-
countVectorizableCol = Math.max(countVectorizableCol, nColumns);
|
|
20528
|
-
countVectorizableRow = Math.max(countVectorizableRow, nRows);
|
|
20529
|
-
vectorizableColLimit = Math.min(vectorizableColLimit, nColumns);
|
|
20530
|
-
vectorizableRowLimit = Math.min(vectorizableRowLimit, nRows);
|
|
20531
|
-
}
|
|
20532
|
-
else if (nColumns !== 1) {
|
|
20533
|
-
vectorArgsType[i] = "horizontal";
|
|
20534
|
-
countVectorizableCol = Math.max(countVectorizableCol, nColumns);
|
|
20535
|
-
vectorizableColLimit = Math.min(vectorizableColLimit, nColumns);
|
|
20536
|
-
}
|
|
20537
|
-
else if (nRows !== 1) {
|
|
20538
|
-
vectorArgsType[i] = "vertical";
|
|
20539
|
-
countVectorizableRow = Math.max(countVectorizableRow, nRows);
|
|
20540
|
-
vectorizableRowLimit = Math.min(vectorizableRowLimit, nRows);
|
|
20541
|
-
}
|
|
20542
|
-
}
|
|
20543
|
-
else {
|
|
20544
|
-
args[i] = arg[0][0];
|
|
20545
|
-
}
|
|
20546
|
-
}
|
|
20547
20677
|
if (!isMatrix(arg) && argDefinition.acceptMatrixOnly) {
|
|
20548
20678
|
throw new BadExpressionError(_t("Function %s expects the parameter '%s' to be reference to a cell or range.", functionName, (i + 1).toString()));
|
|
20549
20679
|
}
|
|
20680
|
+
acceptToVectorize.push(!argDefinition.acceptMatrix);
|
|
20550
20681
|
}
|
|
20551
|
-
|
|
20552
|
-
if (countVectorizableCol === 1 && countVectorizableRow === 1) {
|
|
20553
|
-
// either this function is not vectorized or it ends up with a 1x1 dimension
|
|
20554
|
-
return errorHandlingCompute.apply(this, args);
|
|
20555
|
-
}
|
|
20556
|
-
const getArgOffset = (i, j) => args.map((arg, index) => {
|
|
20557
|
-
switch (vectorArgsType?.[index]) {
|
|
20558
|
-
case "matrix":
|
|
20559
|
-
return arg[i][j];
|
|
20560
|
-
case "horizontal":
|
|
20561
|
-
return arg[i][0];
|
|
20562
|
-
case "vertical":
|
|
20563
|
-
return arg[0][j];
|
|
20564
|
-
case undefined:
|
|
20565
|
-
return arg;
|
|
20566
|
-
}
|
|
20567
|
-
});
|
|
20568
|
-
return generateMatrix(countVectorizableCol, countVectorizableRow, (col, row) => {
|
|
20569
|
-
if (col > vectorizableColLimit - 1 || row > vectorizableRowLimit - 1) {
|
|
20570
|
-
return notAvailableError;
|
|
20571
|
-
}
|
|
20572
|
-
const singleCellComputeResult = errorHandlingCompute.apply(this, getArgOffset(col, row));
|
|
20573
|
-
// In the case where the user tries to vectorize arguments of an array formula, we will get an
|
|
20574
|
-
// array for every combination of the vectorized arguments, which will lead to a 3D matrix and
|
|
20575
|
-
// we won't be able to return the values.
|
|
20576
|
-
// In this case, we keep the first element of each spreading part, just as Excel does, and
|
|
20577
|
-
// create an array with these parts.
|
|
20578
|
-
// For exemple, we have MUNIT(x) that return an unitary matrix of x*x. If we use it with a
|
|
20579
|
-
// range, like MUNIT(A1:A2), we will get two unitary matrices (one for the value in A1 and one
|
|
20580
|
-
// for the value in A2). In this case, we will simply take the first value of each matrix and
|
|
20581
|
-
// return the array [First value of MUNIT(A1), First value of MUNIT(A2)].
|
|
20582
|
-
return isMatrix(singleCellComputeResult)
|
|
20583
|
-
? singleCellComputeResult[0][0]
|
|
20584
|
-
: singleCellComputeResult;
|
|
20585
|
-
});
|
|
20682
|
+
return applyVectorization(errorHandlingCompute.bind(this), args, acceptToVectorize);
|
|
20586
20683
|
}
|
|
20587
20684
|
function errorHandlingCompute(...args) {
|
|
20588
20685
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -21427,7 +21524,7 @@ class AbstractComposerStore extends SpreadsheetStore {
|
|
|
21427
21524
|
proposals &&
|
|
21428
21525
|
!["ARG_SEPARATOR", "LEFT_PAREN", "OPERATOR"].includes(tokenAtCursor.type)) {
|
|
21429
21526
|
const filteredProposals = fuzzyLookup(searchTerm, proposals, (p) => p.fuzzySearchKey || p.text);
|
|
21430
|
-
if (!exactMatch || filteredProposals.length
|
|
21527
|
+
if (!exactMatch || filteredProposals.length) {
|
|
21431
21528
|
proposals = filteredProposals;
|
|
21432
21529
|
}
|
|
21433
21530
|
}
|
|
@@ -41159,12 +41256,13 @@ class StandaloneComposerStore extends AbstractComposerStore {
|
|
|
41159
41256
|
return res;
|
|
41160
41257
|
}
|
|
41161
41258
|
getComposerContent() {
|
|
41259
|
+
let content = this._currentContent;
|
|
41162
41260
|
if (this.editionMode === "inactive") {
|
|
41163
41261
|
// References in the content might not be linked to the current active sheet
|
|
41164
41262
|
// We here force the sheet name prefix for all references that are not in
|
|
41165
41263
|
// the current active sheet
|
|
41166
41264
|
const defaultRangeSheetId = this.args().defaultRangeSheetId;
|
|
41167
|
-
|
|
41265
|
+
content = rangeTokenize(this.args().content)
|
|
41168
41266
|
.map((token) => {
|
|
41169
41267
|
if (token.type === "REFERENCE") {
|
|
41170
41268
|
const range = this.getters.getRangeFromSheetXC(defaultRangeSheetId, token.value);
|
|
@@ -41174,7 +41272,7 @@ class StandaloneComposerStore extends AbstractComposerStore {
|
|
|
41174
41272
|
})
|
|
41175
41273
|
.join("");
|
|
41176
41274
|
}
|
|
41177
|
-
return this.
|
|
41275
|
+
return localizeContent(content, this.getters.getLocale());
|
|
41178
41276
|
}
|
|
41179
41277
|
stopEdition() {
|
|
41180
41278
|
this._stopEdition();
|
|
@@ -45449,6 +45547,9 @@ class PivotMeasureEditor extends owl.Component {
|
|
|
45449
45547
|
}
|
|
45450
45548
|
return undefined;
|
|
45451
45549
|
}
|
|
45550
|
+
get isCalculatedMeasureInvalid() {
|
|
45551
|
+
return this.env.model.getters.getMeasureCompiledFormula(this.props.measure).isBadExpression;
|
|
45552
|
+
}
|
|
45452
45553
|
}
|
|
45453
45554
|
|
|
45454
45555
|
css /* scss */ `
|
|
@@ -46459,7 +46560,9 @@ function compareDimensionValues(dimension, a, b) {
|
|
|
46459
46560
|
return dimension.order === "asc" ? -1 : 1;
|
|
46460
46561
|
}
|
|
46461
46562
|
if (dimension.type === "integer" || dimension.type === "datetime") {
|
|
46462
|
-
return dimension.order === "asc"
|
|
46563
|
+
return dimension.order === "asc"
|
|
46564
|
+
? toNumber(a, DEFAULT_LOCALE) - toNumber(b, DEFAULT_LOCALE)
|
|
46565
|
+
: toNumber(b, DEFAULT_LOCALE) - toNumber(a, DEFAULT_LOCALE);
|
|
46463
46566
|
}
|
|
46464
46567
|
return dimension.order === "asc" ? a.localeCompare(b) : b.localeCompare(a);
|
|
46465
46568
|
}
|
|
@@ -49222,8 +49325,7 @@ class CellComposerStore extends AbstractComposerStore {
|
|
|
49222
49325
|
if (!spreader) {
|
|
49223
49326
|
return undefined;
|
|
49224
49327
|
}
|
|
49225
|
-
|
|
49226
|
-
return cell?.content;
|
|
49328
|
+
return this.getters.getCellText(spreader, { showFormula: true });
|
|
49227
49329
|
}
|
|
49228
49330
|
get currentEditedCell() {
|
|
49229
49331
|
return {
|
|
@@ -52144,6 +52246,7 @@ function useGridDrawing(refName, model, canvasSize) {
|
|
|
52144
52246
|
const friction = 0.95;
|
|
52145
52247
|
const verticalScrollFactor = 1;
|
|
52146
52248
|
const horizontalScrollFactor = 1;
|
|
52249
|
+
const resetTimeoutDuration = 100;
|
|
52147
52250
|
function useTouchScroll(ref, updateScroll, canMoveUp) {
|
|
52148
52251
|
let lastX = 0;
|
|
52149
52252
|
let lastY = 0;
|
|
@@ -52151,6 +52254,7 @@ function useTouchScroll(ref, updateScroll, canMoveUp) {
|
|
|
52151
52254
|
let velocityY = 0;
|
|
52152
52255
|
let isMouseDown = false;
|
|
52153
52256
|
let lastTime = 0;
|
|
52257
|
+
let resetTimeout = null;
|
|
52154
52258
|
useRefListener(ref, "touchstart", onTouchStart, { capture: false });
|
|
52155
52259
|
useRefListener(ref, "touchmove", onTouchMove, { capture: false });
|
|
52156
52260
|
useRefListener(ref, "touchend", onTouchEnd, { capture: false });
|
|
@@ -52163,6 +52267,10 @@ function useTouchScroll(ref, updateScroll, canMoveUp) {
|
|
|
52163
52267
|
function onTouchMove(event) {
|
|
52164
52268
|
if (!isMouseDown)
|
|
52165
52269
|
return;
|
|
52270
|
+
if (resetTimeout) {
|
|
52271
|
+
clearTimeout(resetTimeout);
|
|
52272
|
+
resetTimeout = null;
|
|
52273
|
+
}
|
|
52166
52274
|
const currentTime = Date.now();
|
|
52167
52275
|
const { clientX, clientY } = event.touches[0];
|
|
52168
52276
|
let deltaX = lastX - clientX;
|
|
@@ -52179,6 +52287,10 @@ function useTouchScroll(ref, updateScroll, canMoveUp) {
|
|
|
52179
52287
|
}
|
|
52180
52288
|
event.stopPropagation();
|
|
52181
52289
|
}
|
|
52290
|
+
resetTimeout = setTimeout(() => {
|
|
52291
|
+
velocityX = 0;
|
|
52292
|
+
velocityY = 0;
|
|
52293
|
+
}, resetTimeoutDuration);
|
|
52182
52294
|
updateScroll(deltaX * horizontalScrollFactor, deltaY * verticalScrollFactor);
|
|
52183
52295
|
}
|
|
52184
52296
|
function onTouchEnd(ev) {
|
|
@@ -60951,10 +61063,9 @@ class Evaluator {
|
|
|
60951
61063
|
return this.evaluatedCells.keysForSheet(sheetId);
|
|
60952
61064
|
}
|
|
60953
61065
|
getArrayFormulaSpreadingOn(position) {
|
|
60954
|
-
const
|
|
60955
|
-
|
|
60956
|
-
|
|
60957
|
-
return this.spreadingRelations.isArrayFormula(position) ? position : undefined;
|
|
61066
|
+
const isEmpty = this.getEvaluatedCell(position).type === CellValueType.empty;
|
|
61067
|
+
if (isEmpty) {
|
|
61068
|
+
return undefined;
|
|
60958
61069
|
}
|
|
60959
61070
|
const arrayFormulas = this.spreadingRelations.searchFormulaPositionsSpreadingOn(position.sheetId, positionToZone(position));
|
|
60960
61071
|
return Array.from(arrayFormulas).find((position) => !this.blockedArrayFormulas.has(position));
|
|
@@ -76804,6 +76915,6 @@ exports.tokenColors = tokenColors;
|
|
|
76804
76915
|
exports.tokenize = tokenize;
|
|
76805
76916
|
|
|
76806
76917
|
|
|
76807
|
-
__info__.version = "18.2.
|
|
76808
|
-
__info__.date = "2025-05-
|
|
76809
|
-
__info__.hash = "
|
|
76918
|
+
__info__.version = "18.2.14";
|
|
76919
|
+
__info__.date = "2025-05-26T12:35:51.528Z";
|
|
76920
|
+
__info__.hash = "db90fca";
|