@odoo/o-spreadsheet 18.1.19 → 18.1.21
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 +610 -170
- package/dist/o-spreadsheet.d.ts +318 -192
- package/dist/o-spreadsheet.esm.js +610 -170
- package/dist/o-spreadsheet.iife.js +610 -170
- package/dist/o-spreadsheet.iife.min.js +423 -387
- package/dist/o_spreadsheet.xml +61 -13
- 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.21
|
|
6
|
+
* @date 2025-05-20T05:54:45.398Z
|
|
7
|
+
* @hash 89ed6a9
|
|
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.
|
|
@@ -3347,7 +3306,7 @@
|
|
|
3347
3306
|
*/
|
|
3348
3307
|
const getFormulaNumberRegex = memoize(function getFormulaNumberRegex(decimalSeparator) {
|
|
3349
3308
|
decimalSeparator = escapeRegExp(decimalSeparator);
|
|
3350
|
-
return new RegExp(`(?:^-?\\d+(?:${decimalSeparator}?\\d*(?:e
|
|
3309
|
+
return new RegExp(`(?:^-?\\d+(?:${decimalSeparator}?\\d*(?:e(\\+|-)?\\d+)?)?|^-?${decimalSeparator}\\d+)(?!\\w|!)`);
|
|
3351
3310
|
});
|
|
3352
3311
|
const getNumberRegex = memoize(function getNumberRegex(locale) {
|
|
3353
3312
|
const decimalSeparator = escapeRegExp(locale.decimalSeparator);
|
|
@@ -5966,6 +5925,67 @@
|
|
|
5966
5925
|
return MIN_DELAY + (MAX_DELAY - MIN_DELAY) * Math.exp(-ACCELERATION * (value - 1));
|
|
5967
5926
|
}
|
|
5968
5927
|
|
|
5928
|
+
/** Reference of a cell (eg. A1, $B$5) */
|
|
5929
|
+
const cellReference = new RegExp(/\$?([A-Z]{1,3})\$?([0-9]{1,7})/, "i");
|
|
5930
|
+
// Same as above, but matches the exact string (nothing before or after)
|
|
5931
|
+
const singleCellReference = new RegExp(/^\$?([A-Z]{1,3})\$?([0-9]{1,7})$/, "i");
|
|
5932
|
+
/** Reference of a column header (eg. A, AB, $A) */
|
|
5933
|
+
const colHeader = new RegExp(/^\$?([A-Z]{1,3})+$/, "i");
|
|
5934
|
+
/** Reference of a row header (eg. 1, $1) */
|
|
5935
|
+
const rowHeader = new RegExp(/^\$?([0-9]{1,7})+$/, "i");
|
|
5936
|
+
/** Reference of a column (eg. A, $CA, Sheet1!B) */
|
|
5937
|
+
const colReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([A-Z]{1,3})$/, "i");
|
|
5938
|
+
/** Reference of a row (eg. 1, 59, Sheet1!9) */
|
|
5939
|
+
const rowReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([0-9]{1,7})$/, "i");
|
|
5940
|
+
/** Reference of a normal range or a full row range (eg. A1:B1, 1:$5, $A2:5) */
|
|
5941
|
+
const fullRowXc = /(\$?[A-Z]{1,3})?\$?[0-9]{1,7}\s*:\s*(\$?[A-Z]{1,3})?\$?[0-9]{1,7}\s*/i;
|
|
5942
|
+
/** Reference of a normal range or a column row range (eg. A1:B1, A:$B, $A1:C) */
|
|
5943
|
+
const fullColXc = /\$?[A-Z]{1,3}(\$?[0-9]{1,7})?\s*:\s*\$?[A-Z]{1,3}(\$?[0-9]{1,7})?\s*/i;
|
|
5944
|
+
/** Reference of a cell or a range, it can be a bounded range, a full row or a full column */
|
|
5945
|
+
const rangeReference = new RegExp(/^\s*('.+'!|[^']+!)?/.source +
|
|
5946
|
+
"(" +
|
|
5947
|
+
[cellReference.source, fullRowXc.source, fullColXc.source].join("|") +
|
|
5948
|
+
")" +
|
|
5949
|
+
/$/.source, "i");
|
|
5950
|
+
/**
|
|
5951
|
+
* Return true if the given xc is the reference of a column (e.g. A or AC or Sheet1!A)
|
|
5952
|
+
*/
|
|
5953
|
+
function isColReference(xc) {
|
|
5954
|
+
return colReference.test(xc);
|
|
5955
|
+
}
|
|
5956
|
+
/**
|
|
5957
|
+
* Return true if the given xc is the reference of a column (e.g. 1 or Sheet1!1)
|
|
5958
|
+
*/
|
|
5959
|
+
function isRowReference(xc) {
|
|
5960
|
+
return rowReference.test(xc);
|
|
5961
|
+
}
|
|
5962
|
+
function isColHeader(str) {
|
|
5963
|
+
return colHeader.test(str);
|
|
5964
|
+
}
|
|
5965
|
+
function isRowHeader(str) {
|
|
5966
|
+
return rowHeader.test(str);
|
|
5967
|
+
}
|
|
5968
|
+
/**
|
|
5969
|
+
* Return true if the given xc is the reference of a single cell,
|
|
5970
|
+
* without any specified sheet (e.g. A1)
|
|
5971
|
+
*/
|
|
5972
|
+
function isSingleCellReference(xc) {
|
|
5973
|
+
return singleCellReference.test(xc);
|
|
5974
|
+
}
|
|
5975
|
+
function splitReference(ref) {
|
|
5976
|
+
if (!ref.includes("!")) {
|
|
5977
|
+
return { xc: ref };
|
|
5978
|
+
}
|
|
5979
|
+
const parts = ref.split("!");
|
|
5980
|
+
const xc = parts.pop();
|
|
5981
|
+
const sheetName = getUnquotedSheetName(parts.join("!")) || undefined;
|
|
5982
|
+
return { sheetName, xc };
|
|
5983
|
+
}
|
|
5984
|
+
/** Return a reference SheetName!xc from the given arguments */
|
|
5985
|
+
function getFullReference(sheetName, xc) {
|
|
5986
|
+
return sheetName !== undefined ? `${getCanonicalSymbolName(sheetName)}!${xc}` : xc;
|
|
5987
|
+
}
|
|
5988
|
+
|
|
5969
5989
|
class RangeImpl {
|
|
5970
5990
|
getSheetSize;
|
|
5971
5991
|
_zone;
|
|
@@ -6291,6 +6311,13 @@
|
|
|
6291
6311
|
}
|
|
6292
6312
|
return name;
|
|
6293
6313
|
}
|
|
6314
|
+
function isSheetNameEqual(name1, name2) {
|
|
6315
|
+
if (name1 === undefined || name2 === undefined) {
|
|
6316
|
+
return false;
|
|
6317
|
+
}
|
|
6318
|
+
return (getUnquotedSheetName(name1.trim().toUpperCase()) ===
|
|
6319
|
+
getUnquotedSheetName(name2.trim().toUpperCase()));
|
|
6320
|
+
}
|
|
6294
6321
|
|
|
6295
6322
|
function computeTextLinesHeight(textLineHeight, numberOfLines = 1) {
|
|
6296
6323
|
return numberOfLines * (textLineHeight + MIN_CELL_TEXT_MARGIN) - MIN_CELL_TEXT_MARGIN;
|
|
@@ -8154,10 +8181,9 @@
|
|
|
8154
8181
|
avg: _t("Average"),
|
|
8155
8182
|
sum: _t("Sum"),
|
|
8156
8183
|
};
|
|
8157
|
-
const NUMBER_CHAR_AGGREGATORS = ["max", "min", "avg", "sum", "count_distinct", "count"];
|
|
8158
8184
|
const AGGREGATORS_BY_FIELD_TYPE = {
|
|
8159
|
-
integer:
|
|
8160
|
-
char:
|
|
8185
|
+
integer: ["max", "min", "avg", "sum", "count_distinct", "count"],
|
|
8186
|
+
char: ["count_distinct", "count"],
|
|
8161
8187
|
boolean: ["count_distinct", "count", "bool_and", "bool_or"],
|
|
8162
8188
|
};
|
|
8163
8189
|
const AGGREGATORS = {};
|
|
@@ -9509,7 +9535,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
9509
9535
|
const functionProxy = new Proxy(value, {
|
|
9510
9536
|
// trap the function call
|
|
9511
9537
|
apply(target, thisArg, argArray) {
|
|
9512
|
-
Reflect.apply(target, thisStore, argArray);
|
|
9538
|
+
const res = Reflect.apply(target, thisStore, argArray);
|
|
9539
|
+
if (res === "noStateChange") {
|
|
9540
|
+
return;
|
|
9541
|
+
}
|
|
9513
9542
|
callback();
|
|
9514
9543
|
},
|
|
9515
9544
|
});
|
|
@@ -9531,7 +9560,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
9531
9560
|
const ModelStore = createAbstractStore("Model");
|
|
9532
9561
|
|
|
9533
9562
|
class RendererStore {
|
|
9534
|
-
mutators = ["register", "unRegister"];
|
|
9563
|
+
mutators = ["register", "unRegister", "drawLayer"];
|
|
9535
9564
|
renderers = {};
|
|
9536
9565
|
register(renderer) {
|
|
9537
9566
|
if (!renderer.renderingLayers.length) {
|
|
@@ -9551,14 +9580,14 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
9551
9580
|
}
|
|
9552
9581
|
drawLayer(context, layer) {
|
|
9553
9582
|
const renderers = this.renderers[layer];
|
|
9554
|
-
if (
|
|
9555
|
-
|
|
9556
|
-
|
|
9557
|
-
|
|
9558
|
-
|
|
9559
|
-
|
|
9560
|
-
context.ctx.restore();
|
|
9583
|
+
if (renderers) {
|
|
9584
|
+
for (const renderer of renderers) {
|
|
9585
|
+
context.ctx.save();
|
|
9586
|
+
renderer.drawLayer(context, layer);
|
|
9587
|
+
context.ctx.restore();
|
|
9588
|
+
}
|
|
9561
9589
|
}
|
|
9590
|
+
return "noStateChange";
|
|
9562
9591
|
}
|
|
9563
9592
|
}
|
|
9564
9593
|
|
|
@@ -9611,16 +9640,17 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
9611
9640
|
focusComposer(listener, args) {
|
|
9612
9641
|
this.activeComposer = listener;
|
|
9613
9642
|
if (this.getters.isReadonly()) {
|
|
9614
|
-
return;
|
|
9643
|
+
return "noStateChange";
|
|
9615
9644
|
}
|
|
9616
9645
|
this._focusMode = args.focusMode || "contentFocus";
|
|
9617
9646
|
if (this._focusMode !== "inactive") {
|
|
9618
9647
|
this.setComposerContent(args);
|
|
9619
9648
|
}
|
|
9649
|
+
return;
|
|
9620
9650
|
}
|
|
9621
9651
|
focusActiveComposer(args) {
|
|
9622
9652
|
if (this.getters.isReadonly()) {
|
|
9623
|
-
return;
|
|
9653
|
+
return "noStateChange";
|
|
9624
9654
|
}
|
|
9625
9655
|
if (!this.activeComposer) {
|
|
9626
9656
|
throw new Error("No composer is registered");
|
|
@@ -9629,6 +9659,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
9629
9659
|
if (this._focusMode !== "inactive") {
|
|
9630
9660
|
this.setComposerContent(args);
|
|
9631
9661
|
}
|
|
9662
|
+
return;
|
|
9632
9663
|
}
|
|
9633
9664
|
/**
|
|
9634
9665
|
* Start the edition or update the content if it's already started.
|
|
@@ -9978,7 +10009,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
9978
10009
|
}
|
|
9979
10010
|
function formatChartDatasetValue(axisFormats, locale) {
|
|
9980
10011
|
return (value, axisId) => {
|
|
9981
|
-
const format =
|
|
10012
|
+
const format = axisFormats?.[axisId];
|
|
9982
10013
|
return formatTickValue({ format, locale })(value);
|
|
9983
10014
|
};
|
|
9984
10015
|
}
|
|
@@ -10142,7 +10173,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
10142
10173
|
const y = bar.y + midRadius * Math.sin(midAngle) + 7;
|
|
10143
10174
|
ctx.fillStyle = chartFontColor(options.background);
|
|
10144
10175
|
ctx.strokeStyle = options.background || "#ffffff";
|
|
10145
|
-
const displayValue = options.callback(value);
|
|
10176
|
+
const displayValue = options.callback(value, "y");
|
|
10146
10177
|
drawTextWithBackground(displayValue, x, y, ctx);
|
|
10147
10178
|
}
|
|
10148
10179
|
}
|
|
@@ -19032,6 +19063,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
19032
19063
|
};
|
|
19033
19064
|
}
|
|
19034
19065
|
const domain = pivot.parseArgsToPivotDomain(domainArgs);
|
|
19066
|
+
if (this.getters.getActiveSheetId() === this.__originSheetId) {
|
|
19067
|
+
this.getters.getPivotPresenceTracker(pivotId)?.trackValue(_measure, domain);
|
|
19068
|
+
}
|
|
19035
19069
|
return pivot.getPivotCellValueAndFormat(_measure, domain);
|
|
19036
19070
|
},
|
|
19037
19071
|
};
|
|
@@ -19063,6 +19097,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
19063
19097
|
};
|
|
19064
19098
|
}
|
|
19065
19099
|
const domain = pivot.parseArgsToPivotDomain(domainArgs);
|
|
19100
|
+
if (this.getters.getActiveSheetId() === this.__originSheetId) {
|
|
19101
|
+
this.getters.getPivotPresenceTracker(_pivotId)?.trackHeader(domain);
|
|
19102
|
+
}
|
|
19066
19103
|
const lastNode = domain.at(-1);
|
|
19067
19104
|
if (lastNode?.field === "measure") {
|
|
19068
19105
|
return pivot.getPivotMeasureValue(toString(lastNode.value), domain);
|
|
@@ -19285,6 +19322,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
19285
19322
|
return data === undefined || data.value === null;
|
|
19286
19323
|
}
|
|
19287
19324
|
const getNeutral = { number: 0, string: "", boolean: false };
|
|
19325
|
+
function areAlmostEqual(value1, value2, epsilon = 2e-16) {
|
|
19326
|
+
return Math.abs(value1 - value2) < epsilon;
|
|
19327
|
+
}
|
|
19288
19328
|
const EQ = {
|
|
19289
19329
|
description: _t("Equal."),
|
|
19290
19330
|
args: [
|
|
@@ -19306,6 +19346,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
19306
19346
|
if (typeof _value2 === "string") {
|
|
19307
19347
|
_value2 = _value2.toUpperCase();
|
|
19308
19348
|
}
|
|
19349
|
+
if (typeof _value1 === "number" && typeof _value2 === "number") {
|
|
19350
|
+
return { value: areAlmostEqual(_value1, _value2) };
|
|
19351
|
+
}
|
|
19309
19352
|
return { value: _value1 === _value2 };
|
|
19310
19353
|
},
|
|
19311
19354
|
};
|
|
@@ -19345,6 +19388,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
19345
19388
|
],
|
|
19346
19389
|
compute: function (value1, value2) {
|
|
19347
19390
|
return applyRelationalOperator(value1, value2, (v1, v2) => {
|
|
19391
|
+
if (typeof v1 === "number" && typeof v2 === "number") {
|
|
19392
|
+
return !areAlmostEqual(v1, v2) && v1 > v2;
|
|
19393
|
+
}
|
|
19348
19394
|
return v1 > v2;
|
|
19349
19395
|
});
|
|
19350
19396
|
},
|
|
@@ -19360,6 +19406,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
19360
19406
|
],
|
|
19361
19407
|
compute: function (value1, value2) {
|
|
19362
19408
|
return applyRelationalOperator(value1, value2, (v1, v2) => {
|
|
19409
|
+
if (typeof v1 === "number" && typeof v2 === "number") {
|
|
19410
|
+
return areAlmostEqual(v1, v2) || v1 > v2;
|
|
19411
|
+
}
|
|
19363
19412
|
return v1 >= v2;
|
|
19364
19413
|
});
|
|
19365
19414
|
},
|
|
@@ -20966,7 +21015,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
20966
21015
|
.find((token) => {
|
|
20967
21016
|
const { xc, sheetName: sheet } = splitReference(token.value);
|
|
20968
21017
|
const sheetName = sheet || this.getters.getSheetName(this.sheetId);
|
|
20969
|
-
if (this.getters.getSheetName(activeSheetId)
|
|
21018
|
+
if (!isSheetNameEqual(this.getters.getSheetName(activeSheetId), sheetName)) {
|
|
20970
21019
|
return false;
|
|
20971
21020
|
}
|
|
20972
21021
|
const refRange = this.getters.getRangeFromSheetXC(activeSheetId, xc);
|
|
@@ -24577,7 +24626,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
24577
24626
|
({ xc, sheetName } = splitReference(reference));
|
|
24578
24627
|
let rangeSheetIndex;
|
|
24579
24628
|
if (sheetName) {
|
|
24580
|
-
const index = data.sheets.findIndex((sheet) => sheet.name
|
|
24629
|
+
const index = data.sheets.findIndex((sheet) => isSheetNameEqual(sheet.name, sheetName));
|
|
24581
24630
|
if (index < 0) {
|
|
24582
24631
|
throw new Error("Unable to find a sheet with the name " + sheetName);
|
|
24583
24632
|
}
|
|
@@ -24918,7 +24967,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
24918
24967
|
formula = formula.replace(externalReferenceRegex, (match, externalRefId, sheetName, cellRef) => {
|
|
24919
24968
|
externalRefId = Number(externalRefId) - 1;
|
|
24920
24969
|
cellRef = cellRef.replace(/\$/g, "");
|
|
24921
|
-
const sheetIndex = data.externalBooks[externalRefId].sheetNames.findIndex((name) => name
|
|
24970
|
+
const sheetIndex = data.externalBooks[externalRefId].sheetNames.findIndex((name) => isSheetNameEqual(name, sheetName));
|
|
24922
24971
|
if (sheetIndex === -1) {
|
|
24923
24972
|
return match;
|
|
24924
24973
|
}
|
|
@@ -25569,7 +25618,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
25569
25618
|
*/
|
|
25570
25619
|
function convertTableFormulaReferences(convertedSheets, xlsxSheets) {
|
|
25571
25620
|
for (let tableSheet of convertedSheets) {
|
|
25572
|
-
const tables = xlsxSheets.find((s) => s.sheetName
|
|
25621
|
+
const tables = xlsxSheets.find((s) => isSheetNameEqual(s.sheetName, tableSheet.name)).tables;
|
|
25573
25622
|
for (let table of tables) {
|
|
25574
25623
|
const tabRef = table.name + "[";
|
|
25575
25624
|
for (let sheet of convertedSheets) {
|
|
@@ -32404,12 +32453,20 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
32404
32453
|
}
|
|
32405
32454
|
}
|
|
32406
32455
|
hover(position) {
|
|
32456
|
+
if (position.col === this.col && position.row === this.row) {
|
|
32457
|
+
return "noStateChange";
|
|
32458
|
+
}
|
|
32407
32459
|
this.col = position.col;
|
|
32408
32460
|
this.row = position.row;
|
|
32461
|
+
return;
|
|
32409
32462
|
}
|
|
32410
32463
|
clear() {
|
|
32464
|
+
if (this.col === undefined && this.row === undefined) {
|
|
32465
|
+
return "noStateChange";
|
|
32466
|
+
}
|
|
32411
32467
|
this.col = undefined;
|
|
32412
32468
|
this.row = undefined;
|
|
32469
|
+
return;
|
|
32413
32470
|
}
|
|
32414
32471
|
}
|
|
32415
32472
|
|
|
@@ -32431,7 +32488,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
32431
32488
|
this.persistentPopover = { col, row, sheetId, type };
|
|
32432
32489
|
}
|
|
32433
32490
|
close() {
|
|
32491
|
+
if (!this.persistentPopover) {
|
|
32492
|
+
return "noStateChange";
|
|
32493
|
+
}
|
|
32434
32494
|
this.persistentPopover = undefined;
|
|
32495
|
+
return;
|
|
32435
32496
|
}
|
|
32436
32497
|
get persistentCellPopover() {
|
|
32437
32498
|
return ((this.persistentPopover && { isOpen: true, ...this.persistentPopover }) || { isOpen: false });
|
|
@@ -40263,10 +40324,18 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
40263
40324
|
}
|
|
40264
40325
|
|
|
40265
40326
|
class DOMFocusableElementStore {
|
|
40266
|
-
mutators = ["setFocusableElement"];
|
|
40327
|
+
mutators = ["setFocusableElement", "focus"];
|
|
40267
40328
|
focusableElement = undefined;
|
|
40268
40329
|
setFocusableElement(element) {
|
|
40269
40330
|
this.focusableElement = element;
|
|
40331
|
+
return "noStateChange";
|
|
40332
|
+
}
|
|
40333
|
+
focus() {
|
|
40334
|
+
if (this.focusableElement === document.activeElement) {
|
|
40335
|
+
return "noStateChange";
|
|
40336
|
+
}
|
|
40337
|
+
this.focusableElement?.focus();
|
|
40338
|
+
return;
|
|
40270
40339
|
}
|
|
40271
40340
|
}
|
|
40272
40341
|
|
|
@@ -40856,7 +40925,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
40856
40925
|
if (document.activeElement === this.contentHelper.el &&
|
|
40857
40926
|
this.props.composerStore.editionMode === "inactive" &&
|
|
40858
40927
|
!this.props.isDefaultFocus) {
|
|
40859
|
-
this.DOMFocusableElementStore.
|
|
40928
|
+
this.DOMFocusableElementStore.focus();
|
|
40860
40929
|
}
|
|
40861
40930
|
});
|
|
40862
40931
|
owl.useEffect(() => {
|
|
@@ -41296,12 +41365,13 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
41296
41365
|
return providersDefinitions;
|
|
41297
41366
|
}
|
|
41298
41367
|
getComposerContent() {
|
|
41368
|
+
let content = this._currentContent;
|
|
41299
41369
|
if (this.editionMode === "inactive") {
|
|
41300
41370
|
// References in the content might not be linked to the current active sheet
|
|
41301
41371
|
// We here force the sheet name prefix for all references that are not in
|
|
41302
41372
|
// the current active sheet
|
|
41303
41373
|
const defaultRangeSheetId = this.args().defaultRangeSheetId;
|
|
41304
|
-
|
|
41374
|
+
content = rangeTokenize(this.args().content)
|
|
41305
41375
|
.map((token) => {
|
|
41306
41376
|
if (token.type === "REFERENCE") {
|
|
41307
41377
|
const range = this.getters.getRangeFromSheetXC(defaultRangeSheetId, token.value);
|
|
@@ -41311,7 +41381,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
41311
41381
|
})
|
|
41312
41382
|
.join("");
|
|
41313
41383
|
}
|
|
41314
|
-
return this.
|
|
41384
|
+
return localizeContent(content, this.getters.getLocale());
|
|
41315
41385
|
}
|
|
41316
41386
|
stopEdition() {
|
|
41317
41387
|
this._stopEdition();
|
|
@@ -45057,6 +45127,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45057
45127
|
}
|
|
45058
45128
|
return undefined;
|
|
45059
45129
|
}
|
|
45130
|
+
get isCalculatedMeasureInvalid() {
|
|
45131
|
+
return this.env.model.getters.getMeasureCompiledFormula(this.props.measure).isBadExpression;
|
|
45132
|
+
}
|
|
45060
45133
|
}
|
|
45061
45134
|
|
|
45062
45135
|
css /* scss */ `
|
|
@@ -46603,7 +46676,12 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46603
46676
|
entry[field.name] = { value: null, type: CellValueType.empty, formattedValue: "" };
|
|
46604
46677
|
}
|
|
46605
46678
|
else {
|
|
46606
|
-
|
|
46679
|
+
if (field.type === "char") {
|
|
46680
|
+
entry[field.name] = { ...cell, value: cell.formattedValue || null };
|
|
46681
|
+
}
|
|
46682
|
+
else {
|
|
46683
|
+
entry[field.name] = cell;
|
|
46684
|
+
}
|
|
46607
46685
|
}
|
|
46608
46686
|
}
|
|
46609
46687
|
entry["__count"] = { value: 1, type: CellValueType.number, formattedValue: "1" };
|
|
@@ -51632,10 +51710,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
51632
51710
|
ctx.scale(dpr, dpr);
|
|
51633
51711
|
for (const layer of OrderedLayers()) {
|
|
51634
51712
|
model.drawLayer(renderingContext, layer);
|
|
51635
|
-
// @ts-ignore 'drawLayer' is not declated as a mutator because:
|
|
51636
|
-
// it does not mutate anything. Most importantly it's used
|
|
51637
|
-
// during rendering. Invoking a mutator during rendering would
|
|
51638
|
-
// trigger another rendering, ultimately resulting in an infinite loop.
|
|
51639
51713
|
rendererStore.drawLayer(renderingContext, layer);
|
|
51640
51714
|
}
|
|
51641
51715
|
}
|
|
@@ -52325,7 +52399,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
52325
52399
|
this.cellPopovers = useStore(CellPopoverStore);
|
|
52326
52400
|
owl.useEffect(() => {
|
|
52327
52401
|
if (!this.sidePanel.isOpen) {
|
|
52328
|
-
this.DOMFocusableElementStore.
|
|
52402
|
+
this.DOMFocusableElementStore.focus();
|
|
52329
52403
|
}
|
|
52330
52404
|
}, () => [this.sidePanel.isOpen]);
|
|
52331
52405
|
useTouchScroll(this.gridRef, this.moveCanvas.bind(this), () => {
|
|
@@ -52535,7 +52609,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
52535
52609
|
focusDefaultElement() {
|
|
52536
52610
|
if (!this.env.model.getters.getSelectedFigureId() &&
|
|
52537
52611
|
this.composerFocusStore.activeComposer.editionMode === "inactive") {
|
|
52538
|
-
this.DOMFocusableElementStore.
|
|
52612
|
+
this.DOMFocusableElementStore.focus();
|
|
52539
52613
|
}
|
|
52540
52614
|
}
|
|
52541
52615
|
get gridEl() {
|
|
@@ -52880,6 +52954,322 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
52880
52954
|
}
|
|
52881
52955
|
}
|
|
52882
52956
|
|
|
52957
|
+
css /* scss */ `
|
|
52958
|
+
.o_pivot_html_renderer {
|
|
52959
|
+
width: 100%;
|
|
52960
|
+
border-collapse: collapse;
|
|
52961
|
+
|
|
52962
|
+
&:hover {
|
|
52963
|
+
cursor: pointer;
|
|
52964
|
+
}
|
|
52965
|
+
|
|
52966
|
+
td,
|
|
52967
|
+
th {
|
|
52968
|
+
border: 1px solid #dee2e6;
|
|
52969
|
+
background-color: #fff;
|
|
52970
|
+
padding: 0.3rem;
|
|
52971
|
+
white-space: nowrap;
|
|
52972
|
+
|
|
52973
|
+
&:hover {
|
|
52974
|
+
filter: brightness(0.9);
|
|
52975
|
+
}
|
|
52976
|
+
}
|
|
52977
|
+
|
|
52978
|
+
td {
|
|
52979
|
+
text-align: right;
|
|
52980
|
+
}
|
|
52981
|
+
|
|
52982
|
+
th {
|
|
52983
|
+
background-color: #f5f5f5;
|
|
52984
|
+
font-weight: bold;
|
|
52985
|
+
color: black;
|
|
52986
|
+
}
|
|
52987
|
+
|
|
52988
|
+
.o_missing_value {
|
|
52989
|
+
color: #46646d;
|
|
52990
|
+
background: #e7f2f6;
|
|
52991
|
+
}
|
|
52992
|
+
}
|
|
52993
|
+
`;
|
|
52994
|
+
class PivotHTMLRenderer extends owl.Component {
|
|
52995
|
+
static template = "o_spreadsheet.PivotHTMLRenderer";
|
|
52996
|
+
static components = { Checkbox };
|
|
52997
|
+
static props = {
|
|
52998
|
+
pivotId: String,
|
|
52999
|
+
onCellClicked: Function,
|
|
53000
|
+
};
|
|
53001
|
+
pivot = this.env.model.getters.getPivot(this.props.pivotId);
|
|
53002
|
+
data = {
|
|
53003
|
+
columns: [],
|
|
53004
|
+
rows: [],
|
|
53005
|
+
values: [],
|
|
53006
|
+
};
|
|
53007
|
+
state = owl.useState({
|
|
53008
|
+
showMissingValuesOnly: false,
|
|
53009
|
+
});
|
|
53010
|
+
setup() {
|
|
53011
|
+
const table = this.pivot.getTableStructure();
|
|
53012
|
+
const formulaId = this.env.model.getters.getPivotFormulaId(this.props.pivotId);
|
|
53013
|
+
this.data = {
|
|
53014
|
+
columns: this._buildColHeaders(formulaId, table),
|
|
53015
|
+
rows: this._buildRowHeaders(formulaId, table),
|
|
53016
|
+
values: this._buildValues(formulaId, table),
|
|
53017
|
+
};
|
|
53018
|
+
}
|
|
53019
|
+
get tracker() {
|
|
53020
|
+
return this.env.model.getters.getPivotPresenceTracker(this.props.pivotId);
|
|
53021
|
+
}
|
|
53022
|
+
// ---------------------------------------------------------------------
|
|
53023
|
+
// Missing values building
|
|
53024
|
+
// ---------------------------------------------------------------------
|
|
53025
|
+
/**
|
|
53026
|
+
* Retrieve the data to display in the Pivot Table
|
|
53027
|
+
* In the case when showMissingValuesOnly is false, the returned value
|
|
53028
|
+
* is the complete data
|
|
53029
|
+
* In the case when showMissingValuesOnly is true, the returned value is
|
|
53030
|
+
* the data which contains only missing values in the rows and cols. In
|
|
53031
|
+
* the rows, we also return the parent rows of rows which contains missing
|
|
53032
|
+
* values, to give context to the user.
|
|
53033
|
+
*
|
|
53034
|
+
*/
|
|
53035
|
+
getTableData() {
|
|
53036
|
+
if (!this.state.showMissingValuesOnly) {
|
|
53037
|
+
return this.data;
|
|
53038
|
+
}
|
|
53039
|
+
const colIndexes = this.getColumnsIndexes();
|
|
53040
|
+
const rowIndexes = this.getRowsIndexes();
|
|
53041
|
+
const columns = this.buildColumnsMissing(colIndexes);
|
|
53042
|
+
const rows = this.buildRowsMissing(rowIndexes);
|
|
53043
|
+
const values = this.buildValuesMissing(colIndexes, rowIndexes);
|
|
53044
|
+
return { columns, rows, values };
|
|
53045
|
+
}
|
|
53046
|
+
/**
|
|
53047
|
+
* Retrieve the parents of the given row
|
|
53048
|
+
* ex:
|
|
53049
|
+
* Australia
|
|
53050
|
+
* January
|
|
53051
|
+
* February
|
|
53052
|
+
* The parent of "January" is "Australia"
|
|
53053
|
+
*/
|
|
53054
|
+
addRecursiveRow(index) {
|
|
53055
|
+
const rows = this.pivot.getTableStructure().rows;
|
|
53056
|
+
const row = [...rows[index].values];
|
|
53057
|
+
if (row.length <= 1) {
|
|
53058
|
+
return [index];
|
|
53059
|
+
}
|
|
53060
|
+
row.pop();
|
|
53061
|
+
const parentRowIndex = rows.findIndex((r) => JSON.stringify(r.values) === JSON.stringify(row));
|
|
53062
|
+
return [index].concat(this.addRecursiveRow(parentRowIndex));
|
|
53063
|
+
}
|
|
53064
|
+
/**
|
|
53065
|
+
* Create the columns to be used, based on the indexes of the columns in
|
|
53066
|
+
* which a missing value is present
|
|
53067
|
+
*
|
|
53068
|
+
*/
|
|
53069
|
+
buildColumnsMissing(indexes) {
|
|
53070
|
+
// columnsMap explode the columns in an array of array of the same
|
|
53071
|
+
// size with the index of each column, repeated 'span' times.
|
|
53072
|
+
// ex:
|
|
53073
|
+
// | A | B |
|
|
53074
|
+
// | 1 | 2 | 3 |
|
|
53075
|
+
// => [
|
|
53076
|
+
// [0, 0, 1]
|
|
53077
|
+
// [0, 1, 2]
|
|
53078
|
+
// ]
|
|
53079
|
+
const columnsMap = [];
|
|
53080
|
+
for (const column of this.data.columns) {
|
|
53081
|
+
const columnMap = [];
|
|
53082
|
+
for (const index in column) {
|
|
53083
|
+
for (let i = 0; i < column[index].span; i++) {
|
|
53084
|
+
columnMap.push(parseInt(index, 10));
|
|
53085
|
+
}
|
|
53086
|
+
}
|
|
53087
|
+
columnsMap.push(columnMap);
|
|
53088
|
+
}
|
|
53089
|
+
// Remove the columns that are not present in indexes
|
|
53090
|
+
for (let i = columnsMap[columnsMap.length - 1].length; i >= 0; i--) {
|
|
53091
|
+
if (!indexes.includes(i)) {
|
|
53092
|
+
for (const columnMap of columnsMap) {
|
|
53093
|
+
columnMap.splice(i, 1);
|
|
53094
|
+
}
|
|
53095
|
+
}
|
|
53096
|
+
}
|
|
53097
|
+
// Build the columns
|
|
53098
|
+
const columns = [];
|
|
53099
|
+
for (const mapIndex in columnsMap) {
|
|
53100
|
+
const column = [];
|
|
53101
|
+
let index = undefined;
|
|
53102
|
+
let span = 1;
|
|
53103
|
+
for (let i = 0; i < columnsMap[mapIndex].length; i++) {
|
|
53104
|
+
if (index !== columnsMap[mapIndex][i]) {
|
|
53105
|
+
if (index !== undefined) {
|
|
53106
|
+
column.push(Object.assign({}, this.data.columns[mapIndex][index], { span }));
|
|
53107
|
+
}
|
|
53108
|
+
index = columnsMap[mapIndex][i];
|
|
53109
|
+
span = 1;
|
|
53110
|
+
}
|
|
53111
|
+
else {
|
|
53112
|
+
span++;
|
|
53113
|
+
}
|
|
53114
|
+
}
|
|
53115
|
+
if (index !== undefined) {
|
|
53116
|
+
column.push(Object.assign({}, this.data.columns[mapIndex][index], { span }));
|
|
53117
|
+
}
|
|
53118
|
+
columns.push(column);
|
|
53119
|
+
}
|
|
53120
|
+
return columns;
|
|
53121
|
+
}
|
|
53122
|
+
/**
|
|
53123
|
+
* Create the rows to be used, based on the indexes of the rows in
|
|
53124
|
+
* which a missing value is present.
|
|
53125
|
+
*/
|
|
53126
|
+
buildRowsMissing(indexes) {
|
|
53127
|
+
return indexes.map((index) => this.data.rows[index]);
|
|
53128
|
+
}
|
|
53129
|
+
/**
|
|
53130
|
+
* Create the value to be used, based on the indexes of the columns and
|
|
53131
|
+
* rows in which a missing value is present.
|
|
53132
|
+
*/
|
|
53133
|
+
buildValuesMissing(colIndexes, rowIndexes) {
|
|
53134
|
+
const values = colIndexes.map(() => []);
|
|
53135
|
+
for (const row of rowIndexes) {
|
|
53136
|
+
for (const col in colIndexes) {
|
|
53137
|
+
values[col].push(this.data.values[colIndexes[col]][row]);
|
|
53138
|
+
}
|
|
53139
|
+
}
|
|
53140
|
+
return values;
|
|
53141
|
+
}
|
|
53142
|
+
getColumnsIndexes() {
|
|
53143
|
+
const indexes = new Set();
|
|
53144
|
+
for (let i = 0; i < this.data.columns.length; i++) {
|
|
53145
|
+
const exploded = [];
|
|
53146
|
+
for (let y = 0; y < this.data.columns[i].length; y++) {
|
|
53147
|
+
for (let x = 0; x < this.data.columns[i][y].span; x++) {
|
|
53148
|
+
exploded.push(this.data.columns[i][y]);
|
|
53149
|
+
}
|
|
53150
|
+
}
|
|
53151
|
+
for (let y = 0; y < exploded.length; y++) {
|
|
53152
|
+
if (exploded[y].isMissing) {
|
|
53153
|
+
indexes.add(y);
|
|
53154
|
+
}
|
|
53155
|
+
}
|
|
53156
|
+
}
|
|
53157
|
+
for (let i = 0; i < this.data.columns[this.data.columns.length - 1].length; i++) {
|
|
53158
|
+
const values = this.data.values[i];
|
|
53159
|
+
if (values.find((x) => x.isMissing)) {
|
|
53160
|
+
indexes.add(i);
|
|
53161
|
+
}
|
|
53162
|
+
}
|
|
53163
|
+
return Array.from(indexes).sort((a, b) => a - b);
|
|
53164
|
+
}
|
|
53165
|
+
getRowsIndexes() {
|
|
53166
|
+
const rowIndexes = new Set();
|
|
53167
|
+
for (let i = 0; i < this.data.rows.length; i++) {
|
|
53168
|
+
if (this.data.rows[i].isMissing) {
|
|
53169
|
+
rowIndexes.add(i);
|
|
53170
|
+
}
|
|
53171
|
+
for (const col of this.data.values) {
|
|
53172
|
+
if (col[i].isMissing) {
|
|
53173
|
+
this.addRecursiveRow(i).forEach((x) => rowIndexes.add(x));
|
|
53174
|
+
}
|
|
53175
|
+
}
|
|
53176
|
+
}
|
|
53177
|
+
return Array.from(rowIndexes).sort((a, b) => a - b);
|
|
53178
|
+
}
|
|
53179
|
+
// ---------------------------------------------------------------------
|
|
53180
|
+
// Data table creation
|
|
53181
|
+
// ---------------------------------------------------------------------
|
|
53182
|
+
_buildColHeaders(id, table) {
|
|
53183
|
+
const headers = [];
|
|
53184
|
+
for (const row of table.columns) {
|
|
53185
|
+
const current = [];
|
|
53186
|
+
for (const cell of row) {
|
|
53187
|
+
const args = [];
|
|
53188
|
+
for (let i = 0; i < cell.fields.length; i++) {
|
|
53189
|
+
args.push({ value: cell.fields[i] }, { value: cell.values[i] });
|
|
53190
|
+
}
|
|
53191
|
+
const domain = this.pivot.parseArgsToPivotDomain(args);
|
|
53192
|
+
const locale = this.env.model.getters.getLocale();
|
|
53193
|
+
if (domain.at(-1)?.field === "measure") {
|
|
53194
|
+
const { value, format } = this.pivot.getPivotMeasureValue(toString(domain.at(-1).value), domain);
|
|
53195
|
+
current.push({
|
|
53196
|
+
formula: `=PIVOT.HEADER(${generatePivotArgs(id, domain).join(",")})`,
|
|
53197
|
+
value: formatValue(value, { format, locale }),
|
|
53198
|
+
span: cell.width,
|
|
53199
|
+
isMissing: !this.tracker?.isHeaderPresent(domain),
|
|
53200
|
+
});
|
|
53201
|
+
}
|
|
53202
|
+
else {
|
|
53203
|
+
const { value, format } = this.pivot.getPivotHeaderValueAndFormat(domain);
|
|
53204
|
+
current.push({
|
|
53205
|
+
formula: `=PIVOT.HEADER(${generatePivotArgs(id, domain).join(",")})`,
|
|
53206
|
+
value: formatValue(value, { format, locale }),
|
|
53207
|
+
span: cell.width,
|
|
53208
|
+
isMissing: !this.tracker?.isHeaderPresent(domain),
|
|
53209
|
+
});
|
|
53210
|
+
}
|
|
53211
|
+
}
|
|
53212
|
+
headers.push(current);
|
|
53213
|
+
}
|
|
53214
|
+
const last = headers[headers.length - 1];
|
|
53215
|
+
headers[headers.length - 1] = last.map((cell) => {
|
|
53216
|
+
if (!cell.isMissing) {
|
|
53217
|
+
cell.style = "color: #756f6f;";
|
|
53218
|
+
}
|
|
53219
|
+
return cell;
|
|
53220
|
+
});
|
|
53221
|
+
return headers;
|
|
53222
|
+
}
|
|
53223
|
+
_buildRowHeaders(id, table) {
|
|
53224
|
+
const headers = [];
|
|
53225
|
+
for (const row of table.rows) {
|
|
53226
|
+
const args = [];
|
|
53227
|
+
for (let i = 0; i < row.fields.length; i++) {
|
|
53228
|
+
args.push({ value: row.fields[i] }, { value: row.values[i] });
|
|
53229
|
+
}
|
|
53230
|
+
const domain = this.pivot.parseArgsToPivotDomain(args);
|
|
53231
|
+
const { value, format } = this.pivot.getPivotHeaderValueAndFormat(domain);
|
|
53232
|
+
const locale = this.env.model.getters.getLocale();
|
|
53233
|
+
const cell = {
|
|
53234
|
+
formula: `=PIVOT.HEADER(${generatePivotArgs(id, domain).join(",")})`,
|
|
53235
|
+
value: formatValue(value, { format, locale }),
|
|
53236
|
+
isMissing: !this.tracker?.isHeaderPresent(domain),
|
|
53237
|
+
};
|
|
53238
|
+
if (row.indent > 1) {
|
|
53239
|
+
cell.style = `padding-left: ${row.indent - 1 * 10}px`;
|
|
53240
|
+
}
|
|
53241
|
+
headers.push(cell);
|
|
53242
|
+
}
|
|
53243
|
+
return headers;
|
|
53244
|
+
}
|
|
53245
|
+
_buildValues(id, table) {
|
|
53246
|
+
const values = [];
|
|
53247
|
+
for (const col of table.columns.at(-1) || []) {
|
|
53248
|
+
const current = [];
|
|
53249
|
+
const measure = toString(col.values[col.values.length - 1]);
|
|
53250
|
+
for (const row of table.rows) {
|
|
53251
|
+
const args = [];
|
|
53252
|
+
for (let i = 0; i < row.fields.length; i++) {
|
|
53253
|
+
args.push({ value: row.fields[i] }, { value: row.values[i] });
|
|
53254
|
+
}
|
|
53255
|
+
for (let i = 0; i < col.fields.length - 1; i++) {
|
|
53256
|
+
args.push({ value: col.fields[i] }, { value: col.values[i] });
|
|
53257
|
+
}
|
|
53258
|
+
const domain = this.pivot.parseArgsToPivotDomain(args);
|
|
53259
|
+
const { value, format } = this.pivot.getPivotCellValueAndFormat(measure, domain);
|
|
53260
|
+
const locale = this.env.model.getters.getLocale();
|
|
53261
|
+
current.push({
|
|
53262
|
+
formula: `=PIVOT.VALUE(${generatePivotArgs(id, domain, measure).join(",")})`,
|
|
53263
|
+
value: formatValue(value, { format, locale }),
|
|
53264
|
+
isMissing: !this.tracker?.isValuePresent(measure, domain),
|
|
53265
|
+
});
|
|
53266
|
+
}
|
|
53267
|
+
values.push(current);
|
|
53268
|
+
}
|
|
53269
|
+
return values;
|
|
53270
|
+
}
|
|
53271
|
+
}
|
|
53272
|
+
|
|
52883
53273
|
/**
|
|
52884
53274
|
* BasePlugin
|
|
52885
53275
|
*
|
|
@@ -56317,7 +56707,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
56317
56707
|
if (range.sheetId === cmd.sheetId) {
|
|
56318
56708
|
return { changeType: "CHANGE", range };
|
|
56319
56709
|
}
|
|
56320
|
-
if (
|
|
56710
|
+
if (isSheetNameEqual(range.invalidSheetName, cmd.name)) {
|
|
56321
56711
|
const invalidSheetName = undefined;
|
|
56322
56712
|
const sheetId = cmd.sheetId;
|
|
56323
56713
|
const newRange = range.clone({ sheetId, invalidSheetName });
|
|
@@ -56902,7 +57292,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
56902
57292
|
if (name) {
|
|
56903
57293
|
const unquotedName = getUnquotedSheetName(name);
|
|
56904
57294
|
for (const key in this.sheetIdsMapName) {
|
|
56905
|
-
if (key
|
|
57295
|
+
if (isSheetNameEqual(key, unquotedName)) {
|
|
56906
57296
|
return this.sheetIdsMapName[key];
|
|
56907
57297
|
}
|
|
56908
57298
|
}
|
|
@@ -57150,7 +57540,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
57150
57540
|
}
|
|
57151
57541
|
const { orderedSheetIds, sheets } = this;
|
|
57152
57542
|
const name = cmd.name && cmd.name.trim().toLowerCase();
|
|
57153
|
-
if (orderedSheetIds.find((id) => sheets[id]?.name
|
|
57543
|
+
if (orderedSheetIds.find((id) => isSheetNameEqual(sheets[id]?.name, name) && id !== cmd.sheetId)) {
|
|
57154
57544
|
return "DuplicatedSheetName" /* CommandResult.DuplicatedSheetName */;
|
|
57155
57545
|
}
|
|
57156
57546
|
if (FORBIDDEN_SHEETNAME_CHARS_IN_EXCEL_REGEX.test(name)) {
|
|
@@ -60112,10 +60502,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
60112
60502
|
return this.evaluatedCells.keysForSheet(sheetId);
|
|
60113
60503
|
}
|
|
60114
60504
|
getArrayFormulaSpreadingOn(position) {
|
|
60115
|
-
const
|
|
60116
|
-
|
|
60117
|
-
|
|
60118
|
-
return this.spreadingRelations.isArrayFormula(position) ? position : undefined;
|
|
60505
|
+
const isEmpty = this.getEvaluatedCell(position).type === CellValueType.empty;
|
|
60506
|
+
if (isEmpty) {
|
|
60507
|
+
return undefined;
|
|
60119
60508
|
}
|
|
60120
60509
|
const arrayFormulas = this.spreadingRelations.searchFormulaPositionsSpreadingOn(position.sheetId, positionToZone(position));
|
|
60121
60510
|
return Array.from(arrayFormulas).find((position) => !this.blockedArrayFormulas.has(position));
|
|
@@ -66053,6 +66442,55 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
66053
66442
|
}
|
|
66054
66443
|
}
|
|
66055
66444
|
|
|
66445
|
+
class PivotPresenceTracker {
|
|
66446
|
+
trackedValues = new Set();
|
|
66447
|
+
domainToArray(domain) {
|
|
66448
|
+
return domain.flatMap((node) => [node.field, toString(node.value)]);
|
|
66449
|
+
}
|
|
66450
|
+
isValuePresent(measure, domain) {
|
|
66451
|
+
const key = JSON.stringify({ measure, domain: this.domainToArray(domain) });
|
|
66452
|
+
return this.trackedValues.has(key);
|
|
66453
|
+
}
|
|
66454
|
+
isHeaderPresent(domain) {
|
|
66455
|
+
const key = JSON.stringify({ domain: this.domainToArray(domain) });
|
|
66456
|
+
return this.trackedValues.has(key);
|
|
66457
|
+
}
|
|
66458
|
+
trackValue(measure, domain) {
|
|
66459
|
+
const key = JSON.stringify({ measure, domain: this.domainToArray(domain) });
|
|
66460
|
+
this.trackedValues.add(key);
|
|
66461
|
+
}
|
|
66462
|
+
trackHeader(domain) {
|
|
66463
|
+
const key = JSON.stringify({ domain: this.domainToArray(domain) });
|
|
66464
|
+
this.trackedValues.add(key);
|
|
66465
|
+
}
|
|
66466
|
+
}
|
|
66467
|
+
|
|
66468
|
+
class PivotPresencePlugin extends UIPlugin {
|
|
66469
|
+
static getters = ["getPivotPresenceTracker"];
|
|
66470
|
+
trackPresencePivotId;
|
|
66471
|
+
tracker;
|
|
66472
|
+
handle(cmd) {
|
|
66473
|
+
switch (cmd.type) {
|
|
66474
|
+
case "PIVOT_START_PRESENCE_TRACKING":
|
|
66475
|
+
this.tracker = new PivotPresenceTracker();
|
|
66476
|
+
this.trackPresencePivotId = cmd.pivotId;
|
|
66477
|
+
break;
|
|
66478
|
+
case "PIVOT_STOP_PRESENCE_TRACKING":
|
|
66479
|
+
this.trackPresencePivotId = undefined;
|
|
66480
|
+
break;
|
|
66481
|
+
}
|
|
66482
|
+
}
|
|
66483
|
+
getPivotPresenceTracker(pivotId) {
|
|
66484
|
+
if (this.trackPresencePivotId !== pivotId) {
|
|
66485
|
+
return undefined;
|
|
66486
|
+
}
|
|
66487
|
+
if (!this.tracker) {
|
|
66488
|
+
throw new Error("Tracker not initialized");
|
|
66489
|
+
}
|
|
66490
|
+
return this.tracker;
|
|
66491
|
+
}
|
|
66492
|
+
}
|
|
66493
|
+
|
|
66056
66494
|
class SplitToColumnsPlugin extends UIPlugin {
|
|
66057
66495
|
static getters = ["getAutomaticSeparator"];
|
|
66058
66496
|
allowDispatch(cmd) {
|
|
@@ -68840,6 +69278,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
68840
69278
|
.add("automatic_sum", AutomaticSumPlugin)
|
|
68841
69279
|
.add("format", FormatPlugin)
|
|
68842
69280
|
.add("insert_pivot", InsertPivotPlugin)
|
|
69281
|
+
.add("pivot_presence", PivotPresencePlugin)
|
|
68843
69282
|
.add("split_to_columns", SplitToColumnsPlugin)
|
|
68844
69283
|
.add("collaborative", CollaborativePlugin)
|
|
68845
69284
|
.add("history", HistoryPlugin)
|
|
@@ -69220,11 +69659,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
69220
69659
|
if (ev.key === "Enter") {
|
|
69221
69660
|
ev.preventDefault();
|
|
69222
69661
|
this.stopEdition();
|
|
69223
|
-
this.DOMFocusableElementStore.
|
|
69662
|
+
this.DOMFocusableElementStore.focus();
|
|
69224
69663
|
}
|
|
69225
69664
|
if (ev.key === "Escape") {
|
|
69226
69665
|
this.cancelEdition();
|
|
69227
|
-
this.DOMFocusableElementStore.
|
|
69666
|
+
this.DOMFocusableElementStore.focus();
|
|
69228
69667
|
}
|
|
69229
69668
|
}
|
|
69230
69669
|
onMouseEventSheetName(ev) {
|
|
@@ -75815,6 +76254,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
75815
76254
|
PivotDimensionOrder,
|
|
75816
76255
|
PivotDimension,
|
|
75817
76256
|
PivotLayoutConfigurator,
|
|
76257
|
+
PivotHTMLRenderer,
|
|
75818
76258
|
PivotDeferUpdate,
|
|
75819
76259
|
PivotTitleSection,
|
|
75820
76260
|
CogWheelMenu,
|
|
@@ -75908,9 +76348,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
75908
76348
|
exports.tokenize = tokenize;
|
|
75909
76349
|
|
|
75910
76350
|
|
|
75911
|
-
__info__.version = "18.1.
|
|
75912
|
-
__info__.date = "2025-05-
|
|
75913
|
-
__info__.hash = "
|
|
76351
|
+
__info__.version = "18.1.21";
|
|
76352
|
+
__info__.date = "2025-05-20T05:54:45.398Z";
|
|
76353
|
+
__info__.hash = "89ed6a9";
|
|
75914
76354
|
|
|
75915
76355
|
|
|
75916
76356
|
})(this.o_spreadsheet = this.o_spreadsheet || {}, owl);
|