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