@odoo/o-spreadsheet 19.1.0-alpha.12 → 19.1.0-alpha.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/o-spreadsheet-engine.d.ts +53 -25
- package/dist/o-spreadsheet-engine.esm.js +510 -131
- package/dist/o-spreadsheet-engine.iife.js +510 -131
- package/dist/o-spreadsheet-engine.min.iife.js +313 -313
- package/dist/o-spreadsheet.d.ts +371 -388
- package/dist/o_spreadsheet.esm.js +29566 -19200
- package/dist/o_spreadsheet.iife.js +29567 -19201
- package/dist/o_spreadsheet.min.iife.js +335 -317
- package/dist/o_spreadsheet.xml +434 -212
- package/package.json +1 -1
|
@@ -3,8 +3,8 @@
|
|
|
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
5
|
* @version 19.1.0-alpha.3
|
|
6
|
-
* @date 2025-
|
|
7
|
-
* @hash
|
|
6
|
+
* @date 2025-12-02T05:34:07.213Z
|
|
7
|
+
* @hash 04cf666
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
(function (exports) {
|
|
@@ -637,6 +637,7 @@
|
|
|
637
637
|
fontSize: 10,
|
|
638
638
|
fillColor: "",
|
|
639
639
|
textColor: "",
|
|
640
|
+
rotation: 0,
|
|
640
641
|
};
|
|
641
642
|
const DEFAULT_VERTICAL_ALIGN = DEFAULT_STYLE.verticalAlign;
|
|
642
643
|
// Fonts
|
|
@@ -682,7 +683,7 @@
|
|
|
682
683
|
};
|
|
683
684
|
const PIVOT_INDENT = 15;
|
|
684
685
|
const PIVOT_COLLAPSE_ICON_SIZE = 12;
|
|
685
|
-
const PIVOT_MAX_NUMBER_OF_CELLS =
|
|
686
|
+
const PIVOT_MAX_NUMBER_OF_CELLS = 5e5;
|
|
686
687
|
|
|
687
688
|
//------------------------------------------------------------------------------
|
|
688
689
|
// Miscellaneous
|
|
@@ -3108,8 +3109,56 @@
|
|
|
3108
3109
|
return isMatrix(arg) && !isSingleElementMatrix(arg);
|
|
3109
3110
|
}
|
|
3110
3111
|
|
|
3112
|
+
function stackHorizontally(ranges, options) {
|
|
3113
|
+
const matrices = ranges.map(toMatrix);
|
|
3114
|
+
const nbRowsArr = matrices.map((m) => m?.[0]?.length ?? 0);
|
|
3115
|
+
const nbRows = Math.max(...nbRowsArr);
|
|
3116
|
+
if (options?.requireSameRowCount) {
|
|
3117
|
+
const firstLength = nbRowsArr[0];
|
|
3118
|
+
if (nbRowsArr.some((len) => len !== firstLength)) {
|
|
3119
|
+
return new EvaluationError(_t("All ranges in [[FUNCTION_NAME]] must have the same number of columns (got %s).", nbRowsArr.join(", ")));
|
|
3120
|
+
}
|
|
3121
|
+
}
|
|
3122
|
+
const result = [];
|
|
3123
|
+
for (const matrix of matrices) {
|
|
3124
|
+
for (let col = 0; col < matrix.length; col++) {
|
|
3125
|
+
// Fill with nulls if needed
|
|
3126
|
+
const array = Array(nbRows).fill({ value: null });
|
|
3127
|
+
for (let row = 0; row < matrix[col].length; row++) {
|
|
3128
|
+
array[row] = matrix[col][row];
|
|
3129
|
+
}
|
|
3130
|
+
result.push(array);
|
|
3131
|
+
}
|
|
3132
|
+
}
|
|
3133
|
+
return result;
|
|
3134
|
+
}
|
|
3135
|
+
function stackVertically(ranges, options) {
|
|
3136
|
+
const matrices = ranges.map(toMatrix);
|
|
3137
|
+
const nbColsArr = matrices.map((m) => m?.length ?? 0);
|
|
3138
|
+
const nbCols = Math.max(...nbColsArr);
|
|
3139
|
+
if (options?.requireSameColCount) {
|
|
3140
|
+
const firstLength = nbColsArr[0];
|
|
3141
|
+
if (nbColsArr.some((len) => len !== firstLength)) {
|
|
3142
|
+
return new EvaluationError(_t("All ranges in [[FUNCTION_NAME]] must have the same number of columns (got %s).", nbColsArr.join(", ")));
|
|
3143
|
+
}
|
|
3144
|
+
}
|
|
3145
|
+
const nbRows = matrices.reduce((acc, m) => acc + (m?.[0]?.length ?? 0), 0);
|
|
3146
|
+
const result = generateMatrix(nbCols, nbRows, () => ({
|
|
3147
|
+
value: null,
|
|
3148
|
+
}));
|
|
3149
|
+
let currentRow = 0;
|
|
3150
|
+
for (const matrix of matrices) {
|
|
3151
|
+
for (let col = 0; col < matrix.length; col++) {
|
|
3152
|
+
for (let row = 0; row < matrix[col].length; row++) {
|
|
3153
|
+
result[col][currentRow + row] = matrix[col][row];
|
|
3154
|
+
}
|
|
3155
|
+
}
|
|
3156
|
+
currentRow += matrix[0]?.length ?? 0;
|
|
3157
|
+
}
|
|
3158
|
+
return result;
|
|
3159
|
+
}
|
|
3111
3160
|
// -----------------------------------------------------------------------------
|
|
3112
|
-
//
|
|
3161
|
+
// ARRAY.CONSTRAIN
|
|
3113
3162
|
// -----------------------------------------------------------------------------
|
|
3114
3163
|
const ARRAY_CONSTRAIN = {
|
|
3115
3164
|
description: _t("Returns a result array constrained to a specific width and height."),
|
|
@@ -3135,6 +3184,30 @@
|
|
|
3135
3184
|
isExported: false,
|
|
3136
3185
|
};
|
|
3137
3186
|
// -----------------------------------------------------------------------------
|
|
3187
|
+
// ARRAY.LITERAL
|
|
3188
|
+
// -----------------------------------------------------------------------------
|
|
3189
|
+
const ARRAY_LITERAL = {
|
|
3190
|
+
description: _t("Appends ranges vertically and in sequence to return a larger array. All ranges must have the same number of columns."),
|
|
3191
|
+
args: [arg("range (any, range<any>, repeating)", _t("The range to be appended."))],
|
|
3192
|
+
compute: function (...ranges) {
|
|
3193
|
+
return stackVertically(ranges, { requireSameColCount: true });
|
|
3194
|
+
},
|
|
3195
|
+
isExported: false,
|
|
3196
|
+
hidden: true,
|
|
3197
|
+
};
|
|
3198
|
+
// -----------------------------------------------------------------------------
|
|
3199
|
+
// ARRAY.ROW
|
|
3200
|
+
// -----------------------------------------------------------------------------
|
|
3201
|
+
const ARRAY_ROW = {
|
|
3202
|
+
description: _t("Appends ranges horizontally and in sequence to return a larger array. All ranges must have the same number of rows."),
|
|
3203
|
+
args: [arg("range (any, range<any>, repeating)", _t("The range to be appended."))],
|
|
3204
|
+
compute: function (...ranges) {
|
|
3205
|
+
return stackHorizontally(ranges, { requireSameRowCount: true });
|
|
3206
|
+
},
|
|
3207
|
+
isExported: false,
|
|
3208
|
+
hidden: true,
|
|
3209
|
+
};
|
|
3210
|
+
// -----------------------------------------------------------------------------
|
|
3138
3211
|
// CHOOSECOLS
|
|
3139
3212
|
// -----------------------------------------------------------------------------
|
|
3140
3213
|
const CHOOSECOLS = {
|
|
@@ -3280,20 +3353,7 @@
|
|
|
3280
3353
|
description: _t("Appends ranges horizontally and in sequence to return a larger array."),
|
|
3281
3354
|
args: [arg("range (any, range<any>, repeating)", _t("The range to be appended."))],
|
|
3282
3355
|
compute: function (...ranges) {
|
|
3283
|
-
|
|
3284
|
-
const result = [];
|
|
3285
|
-
for (const range of ranges) {
|
|
3286
|
-
const _range = toMatrix(range);
|
|
3287
|
-
for (let col = 0; col < _range.length; col++) {
|
|
3288
|
-
//TODO: fill with #N/A for unavailable values instead of zeroes
|
|
3289
|
-
const array = Array(nbRows).fill({ value: null });
|
|
3290
|
-
for (let row = 0; row < _range[col].length; row++) {
|
|
3291
|
-
array[row] = _range[col][row];
|
|
3292
|
-
}
|
|
3293
|
-
result.push(array);
|
|
3294
|
-
}
|
|
3295
|
-
}
|
|
3296
|
-
return result;
|
|
3356
|
+
return stackHorizontally(ranges);
|
|
3297
3357
|
},
|
|
3298
3358
|
isExported: true,
|
|
3299
3359
|
};
|
|
@@ -3552,22 +3612,7 @@
|
|
|
3552
3612
|
description: _t("Appends ranges vertically and in sequence to return a larger array."),
|
|
3553
3613
|
args: [arg("range (any, range<any>, repeating)", _t("The range to be appended."))],
|
|
3554
3614
|
compute: function (...ranges) {
|
|
3555
|
-
|
|
3556
|
-
const nbRows = ranges.reduce((acc, range) => acc + toMatrix(range)[0].length, 0);
|
|
3557
|
-
const result = Array(nbColumns)
|
|
3558
|
-
.fill([])
|
|
3559
|
-
.map(() => Array(nbRows).fill({ value: 0 })); // TODO fill with #N/A
|
|
3560
|
-
let currentRow = 0;
|
|
3561
|
-
for (const range of ranges) {
|
|
3562
|
-
const _array = toMatrix(range);
|
|
3563
|
-
for (let col = 0; col < _array.length; col++) {
|
|
3564
|
-
for (let row = 0; row < _array[col].length; row++) {
|
|
3565
|
-
result[col][currentRow + row] = _array[col][row];
|
|
3566
|
-
}
|
|
3567
|
-
}
|
|
3568
|
-
currentRow += _array[0].length;
|
|
3569
|
-
}
|
|
3570
|
-
return result;
|
|
3615
|
+
return stackVertically(ranges);
|
|
3571
3616
|
},
|
|
3572
3617
|
isExported: true,
|
|
3573
3618
|
};
|
|
@@ -3627,6 +3672,8 @@
|
|
|
3627
3672
|
var array = /*#__PURE__*/Object.freeze({
|
|
3628
3673
|
__proto__: null,
|
|
3629
3674
|
ARRAY_CONSTRAIN: ARRAY_CONSTRAIN,
|
|
3675
|
+
ARRAY_LITERAL: ARRAY_LITERAL,
|
|
3676
|
+
ARRAY_ROW: ARRAY_ROW,
|
|
3630
3677
|
CHOOSECOLS: CHOOSECOLS,
|
|
3631
3678
|
CHOOSEROWS: CHOOSEROWS,
|
|
3632
3679
|
EXPAND: EXPAND,
|
|
@@ -3648,6 +3695,30 @@
|
|
|
3648
3695
|
WRAPROWS: WRAPROWS
|
|
3649
3696
|
});
|
|
3650
3697
|
|
|
3698
|
+
const DEFAULT_LOCALES = [
|
|
3699
|
+
{
|
|
3700
|
+
name: "English (US)",
|
|
3701
|
+
code: "en_US",
|
|
3702
|
+
thousandsSeparator: ",",
|
|
3703
|
+
decimalSeparator: ".",
|
|
3704
|
+
weekStart: 7, // Sunday
|
|
3705
|
+
dateFormat: "m/d/yyyy",
|
|
3706
|
+
timeFormat: "hh:mm:ss a",
|
|
3707
|
+
formulaArgSeparator: ",",
|
|
3708
|
+
},
|
|
3709
|
+
{
|
|
3710
|
+
name: "French",
|
|
3711
|
+
code: "fr_FR",
|
|
3712
|
+
thousandsSeparator: " ",
|
|
3713
|
+
decimalSeparator: ",",
|
|
3714
|
+
weekStart: 1, // Monday
|
|
3715
|
+
dateFormat: "dd/mm/yyyy",
|
|
3716
|
+
timeFormat: "hh:mm:ss",
|
|
3717
|
+
formulaArgSeparator: ";",
|
|
3718
|
+
},
|
|
3719
|
+
];
|
|
3720
|
+
const DEFAULT_LOCALE = DEFAULT_LOCALES[0];
|
|
3721
|
+
|
|
3651
3722
|
function tokenizeFormat(str) {
|
|
3652
3723
|
const chars = new TokenizingChars(str);
|
|
3653
3724
|
const result = [];
|
|
@@ -3932,7 +4003,7 @@
|
|
|
3932
4003
|
}
|
|
3933
4004
|
function parseDateFormatTokens(tokens) {
|
|
3934
4005
|
const internalFormat = tokens && areValidDateFormatTokens(tokens) ? { type: "date", tokens } : undefined;
|
|
3935
|
-
if (!internalFormat) {
|
|
4006
|
+
if (!internalFormat || !tokens?.some((token) => token.type === "DATE_PART")) {
|
|
3936
4007
|
return undefined;
|
|
3937
4008
|
}
|
|
3938
4009
|
if (internalFormat.tokens.length &&
|
|
@@ -4169,6 +4240,9 @@
|
|
|
4169
4240
|
return prefix + repeatedChar.repeat(timesToRepeat) + padding + suffix;
|
|
4170
4241
|
}
|
|
4171
4242
|
function applyInternalNumberFormat(value, format, locale) {
|
|
4243
|
+
if (!format.integerPart.length && !format.decimalPart?.length) {
|
|
4244
|
+
return "";
|
|
4245
|
+
}
|
|
4172
4246
|
if (value === Infinity) {
|
|
4173
4247
|
return "∞" + (format.percentSymbols ? "%" : "");
|
|
4174
4248
|
}
|
|
@@ -4775,7 +4849,7 @@
|
|
|
4775
4849
|
function setXcToFixedReferenceType(xc, referenceType) {
|
|
4776
4850
|
let sheetName;
|
|
4777
4851
|
({ sheetName, xc } = splitReference(xc));
|
|
4778
|
-
sheetName = sheetName ? sheetName + "!" : "";
|
|
4852
|
+
sheetName = sheetName ? getCanonicalSymbolName(sheetName) + "!" : "";
|
|
4779
4853
|
xc = xc.replace(/\$/g, "");
|
|
4780
4854
|
const splitIndex = xc.indexOf(":");
|
|
4781
4855
|
if (splitIndex >= 0) {
|
|
@@ -6055,6 +6129,47 @@
|
|
|
6055
6129
|
return newZones;
|
|
6056
6130
|
}
|
|
6057
6131
|
}
|
|
6132
|
+
/**
|
|
6133
|
+
* Splits zone z2 by removing the overlapping zone z1 (fully inside z2).
|
|
6134
|
+
* Returns the remaining parts of z2 that don't overlap with z1.
|
|
6135
|
+
*
|
|
6136
|
+
* Diagram:
|
|
6137
|
+
* ┌──────────── z2 ─────────────┐
|
|
6138
|
+
* │ 1 │
|
|
6139
|
+
* │--------─────────────--------│
|
|
6140
|
+
* │ 2 | z1 | 3 │
|
|
6141
|
+
* │--------─────────────--------│
|
|
6142
|
+
* │ 4 │
|
|
6143
|
+
* └─────────────────────────────┘
|
|
6144
|
+
*
|
|
6145
|
+
* Input:
|
|
6146
|
+
* z1 = { top: 2, bottom: 3, left: 2, right: 3 }
|
|
6147
|
+
* z2 = { top: 1, bottom: 4, left: 1, right: 4 }
|
|
6148
|
+
*
|
|
6149
|
+
* Output:
|
|
6150
|
+
* [
|
|
6151
|
+
* { top: 4, bottom: 4, left: 1, right: 4 }, // bottom
|
|
6152
|
+
* { top: 2, bottom: 3, left: 4, right: 4 }, // right
|
|
6153
|
+
* { top: 2, bottom: 3, left: 1, right: 1 }, // left
|
|
6154
|
+
* { top: 1, bottom: 1, left: 1, right: 4 } // top
|
|
6155
|
+
* ]
|
|
6156
|
+
*/
|
|
6157
|
+
function splitZone(z1, z2) {
|
|
6158
|
+
const zones = [];
|
|
6159
|
+
if (z1.bottom < z2.bottom) {
|
|
6160
|
+
zones.push({ ...z2, top: z1.bottom + 1 });
|
|
6161
|
+
}
|
|
6162
|
+
if (z1.right < z2.right) {
|
|
6163
|
+
zones.push({ ...z2, left: z1.right + 1, top: z1.top, bottom: z1.bottom });
|
|
6164
|
+
}
|
|
6165
|
+
if (z1.left > z2.left) {
|
|
6166
|
+
zones.push({ ...z2, right: z1.left - 1, top: z1.top, bottom: z1.bottom });
|
|
6167
|
+
}
|
|
6168
|
+
if (z1.top > z2.top) {
|
|
6169
|
+
zones.push({ ...z2, bottom: z1.top - 1 });
|
|
6170
|
+
}
|
|
6171
|
+
return zones;
|
|
6172
|
+
}
|
|
6058
6173
|
|
|
6059
6174
|
function isSheetDependent(cmd) {
|
|
6060
6175
|
return "sheetId" in cmd;
|
|
@@ -6085,7 +6200,6 @@
|
|
|
6085
6200
|
"REDO",
|
|
6086
6201
|
"ADD_MERGE",
|
|
6087
6202
|
"REMOVE_MERGE",
|
|
6088
|
-
"DUPLICATE_SHEET",
|
|
6089
6203
|
"UPDATE_LOCALE",
|
|
6090
6204
|
"ADD_PIVOT",
|
|
6091
6205
|
"UPDATE_PIVOT",
|
|
@@ -7652,7 +7766,7 @@
|
|
|
7652
7766
|
if (!acceptHiddenCells && this.getters.isRowHiddenByUser(sheetId, row))
|
|
7653
7767
|
continue;
|
|
7654
7768
|
for (let col = left; col <= right; col++) {
|
|
7655
|
-
const cell = this.getters.
|
|
7769
|
+
const cell = this.getters.getCorrespondingFormulaCell({ sheetId, col, row });
|
|
7656
7770
|
if (!cell || !isSubtotalCell(cell)) {
|
|
7657
7771
|
evaluatedCellToKeep.push(this.getters.getEvaluatedCell({ sheetId, col, row }));
|
|
7658
7772
|
}
|
|
@@ -9547,30 +9661,6 @@
|
|
|
9547
9661
|
DVARP: DVARP
|
|
9548
9662
|
});
|
|
9549
9663
|
|
|
9550
|
-
const DEFAULT_LOCALES = [
|
|
9551
|
-
{
|
|
9552
|
-
name: "English (US)",
|
|
9553
|
-
code: "en_US",
|
|
9554
|
-
thousandsSeparator: ",",
|
|
9555
|
-
decimalSeparator: ".",
|
|
9556
|
-
weekStart: 7, // Sunday
|
|
9557
|
-
dateFormat: "m/d/yyyy",
|
|
9558
|
-
timeFormat: "hh:mm:ss a",
|
|
9559
|
-
formulaArgSeparator: ",",
|
|
9560
|
-
},
|
|
9561
|
-
{
|
|
9562
|
-
name: "French",
|
|
9563
|
-
code: "fr_FR",
|
|
9564
|
-
thousandsSeparator: " ",
|
|
9565
|
-
decimalSeparator: ",",
|
|
9566
|
-
weekStart: 1, // Monday
|
|
9567
|
-
dateFormat: "dd/mm/yyyy",
|
|
9568
|
-
timeFormat: "hh:mm:ss",
|
|
9569
|
-
formulaArgSeparator: ";",
|
|
9570
|
-
},
|
|
9571
|
-
];
|
|
9572
|
-
const DEFAULT_LOCALE = DEFAULT_LOCALES[0];
|
|
9573
|
-
|
|
9574
9664
|
/**
|
|
9575
9665
|
* Tokenizer
|
|
9576
9666
|
*
|
|
@@ -9599,7 +9689,9 @@
|
|
|
9599
9689
|
while (!chars.isOver()) {
|
|
9600
9690
|
let token = tokenizeNewLine(chars) ||
|
|
9601
9691
|
tokenizeSpace(chars) ||
|
|
9692
|
+
tokenizeArrayRowSeparator(chars, locale) ||
|
|
9602
9693
|
tokenizeArgsSeparator(chars, locale) ||
|
|
9694
|
+
tokenizeBraces(chars) ||
|
|
9603
9695
|
tokenizeParenthesis(chars) ||
|
|
9604
9696
|
tokenizeOperator(chars) ||
|
|
9605
9697
|
tokenizeString(chars) ||
|
|
@@ -9632,6 +9724,17 @@
|
|
|
9632
9724
|
}
|
|
9633
9725
|
return null;
|
|
9634
9726
|
}
|
|
9727
|
+
const braces = {
|
|
9728
|
+
"{": { type: "LEFT_BRACE", value: "{" },
|
|
9729
|
+
"}": { type: "RIGHT_BRACE", value: "}" },
|
|
9730
|
+
};
|
|
9731
|
+
function tokenizeBraces(chars) {
|
|
9732
|
+
if (chars.current === "{" || chars.current === "}") {
|
|
9733
|
+
const value = chars.shift();
|
|
9734
|
+
return braces[value];
|
|
9735
|
+
}
|
|
9736
|
+
return null;
|
|
9737
|
+
}
|
|
9635
9738
|
function tokenizeArgsSeparator(chars, locale) {
|
|
9636
9739
|
if (chars.current === locale.formulaArgSeparator) {
|
|
9637
9740
|
const value = chars.shift();
|
|
@@ -9640,6 +9743,20 @@
|
|
|
9640
9743
|
}
|
|
9641
9744
|
return null;
|
|
9642
9745
|
}
|
|
9746
|
+
function tokenizeArrayRowSeparator(chars, locale) {
|
|
9747
|
+
// The array row separator is used in array literals to separate rows.
|
|
9748
|
+
// It is not explicitly defined in locales, but depends on the formulaArgSeparator.
|
|
9749
|
+
// Example: {1,2,3;4,5,6} — here, ';' separates rows and ',' separates columns.
|
|
9750
|
+
const rowSeparator = locale.formulaArgSeparator === ";" ? "\\" : ";";
|
|
9751
|
+
if (!rowSeparator) {
|
|
9752
|
+
return null;
|
|
9753
|
+
}
|
|
9754
|
+
if (chars.current === rowSeparator) {
|
|
9755
|
+
chars.shift();
|
|
9756
|
+
return { type: "ARRAY_ROW_SEPARATOR", value: rowSeparator };
|
|
9757
|
+
}
|
|
9758
|
+
return null;
|
|
9759
|
+
}
|
|
9643
9760
|
function tokenizeOperator(chars) {
|
|
9644
9761
|
for (const op of OPERATORS) {
|
|
9645
9762
|
if (chars.currentStartsWith(op)) {
|
|
@@ -9860,6 +9977,9 @@
|
|
|
9860
9977
|
else if (token.type === "ARG_SEPARATOR") {
|
|
9861
9978
|
localizedFormula += toLocale.formulaArgSeparator;
|
|
9862
9979
|
}
|
|
9980
|
+
else if (token.type === "ARRAY_ROW_SEPARATOR") {
|
|
9981
|
+
localizedFormula += toLocale.formulaArgSeparator === ";" ? "\\" : ";";
|
|
9982
|
+
}
|
|
9863
9983
|
else {
|
|
9864
9984
|
localizedFormula += token.value;
|
|
9865
9985
|
}
|
|
@@ -11023,7 +11143,6 @@
|
|
|
11023
11143
|
// -----------------------------------------------------------------------------
|
|
11024
11144
|
const FILTER = {
|
|
11025
11145
|
description: _t("Returns a filtered version of the source range, returning only rows or columns that meet the specified conditions."),
|
|
11026
|
-
// TODO modify args description when vectorization on formulas is available
|
|
11027
11146
|
args: [
|
|
11028
11147
|
arg("range (any, range<any>)", _t("The data to be filtered.")),
|
|
11029
11148
|
arg("condition (boolean, range<boolean>, repeating)", _t("Column or row containing true or false values corresponding to the range.")),
|
|
@@ -13975,18 +14094,17 @@
|
|
|
13975
14094
|
["GaugeLowerInflectionPointNaN" /* CommandResult.GaugeLowerInflectionPointNaN */]: _t("The lower inflection point value must be a number"),
|
|
13976
14095
|
["GaugeUpperInflectionPointNaN" /* CommandResult.GaugeUpperInflectionPointNaN */]: _t("The upper inflection point value must be a number"),
|
|
13977
14096
|
},
|
|
13978
|
-
|
|
13979
|
-
|
|
13980
|
-
|
|
13981
|
-
|
|
13982
|
-
|
|
13983
|
-
|
|
13984
|
-
|
|
13985
|
-
|
|
13986
|
-
|
|
13987
|
-
|
|
13988
|
-
|
|
13989
|
-
},
|
|
14097
|
+
ColorScales: {
|
|
14098
|
+
blues: _t("Blues"),
|
|
14099
|
+
cividis: _t("Cividis"),
|
|
14100
|
+
custom: _t("Custom"),
|
|
14101
|
+
greens: _t("Greens"),
|
|
14102
|
+
greys: _t("Greys"),
|
|
14103
|
+
oranges: _t("Oranges"),
|
|
14104
|
+
purples: _t("Purples"),
|
|
14105
|
+
rainbow: _t("Rainbow"),
|
|
14106
|
+
reds: _t("Reds"),
|
|
14107
|
+
viridis: _t("Viridis"),
|
|
13990
14108
|
},
|
|
13991
14109
|
});
|
|
13992
14110
|
({
|
|
@@ -17224,6 +17342,8 @@
|
|
|
17224
17342
|
tokenStartIndex: current.tokenIndex,
|
|
17225
17343
|
tokenEndIndex: rightParen.tokenIndex,
|
|
17226
17344
|
};
|
|
17345
|
+
case "LEFT_BRACE":
|
|
17346
|
+
return parseArrayLiteral(tokens, current);
|
|
17227
17347
|
case "OPERATOR":
|
|
17228
17348
|
const operator = current.value;
|
|
17229
17349
|
if (UNARY_OPERATORS_PREFIX.includes(operator)) {
|
|
@@ -17277,6 +17397,34 @@
|
|
|
17277
17397
|
}
|
|
17278
17398
|
return token;
|
|
17279
17399
|
}
|
|
17400
|
+
function parseArrayLiteral(tokens, leftBrace) {
|
|
17401
|
+
const rows = [];
|
|
17402
|
+
let currentRow = [parseExpression(tokens)]; // there must be at least one element
|
|
17403
|
+
while (tokens.current?.type !== "RIGHT_BRACE") {
|
|
17404
|
+
const nextToken = tokens.shift();
|
|
17405
|
+
if (!nextToken) {
|
|
17406
|
+
throw new BadExpressionError(_t("Missing closing brace"));
|
|
17407
|
+
}
|
|
17408
|
+
else if (nextToken.type === "ARG_SEPARATOR") {
|
|
17409
|
+
currentRow.push(parseExpression(tokens));
|
|
17410
|
+
}
|
|
17411
|
+
else if (nextToken.type === "ARRAY_ROW_SEPARATOR") {
|
|
17412
|
+
rows.push(currentRow);
|
|
17413
|
+
currentRow = [parseExpression(tokens)];
|
|
17414
|
+
}
|
|
17415
|
+
else {
|
|
17416
|
+
throw new BadExpressionError(_t("Unexpected token: %s", nextToken.value));
|
|
17417
|
+
}
|
|
17418
|
+
}
|
|
17419
|
+
const rightBrace = consumeOrThrow(tokens, "RIGHT_BRACE", _t("Missing closing brace"));
|
|
17420
|
+
rows.push(currentRow);
|
|
17421
|
+
return {
|
|
17422
|
+
type: "ARRAY",
|
|
17423
|
+
value: rows,
|
|
17424
|
+
tokenStartIndex: leftBrace.tokenIndex,
|
|
17425
|
+
tokenEndIndex: rightBrace.tokenIndex,
|
|
17426
|
+
};
|
|
17427
|
+
}
|
|
17280
17428
|
function parseExpression(tokens, parent_priority = 0) {
|
|
17281
17429
|
if (tokens.length === 0) {
|
|
17282
17430
|
throw new BadExpressionError();
|
|
@@ -17367,6 +17515,13 @@
|
|
|
17367
17515
|
yield* astIterator(arg);
|
|
17368
17516
|
}
|
|
17369
17517
|
break;
|
|
17518
|
+
case "ARRAY":
|
|
17519
|
+
for (const row of ast.value) {
|
|
17520
|
+
for (const cell of row) {
|
|
17521
|
+
yield* astIterator(cell);
|
|
17522
|
+
}
|
|
17523
|
+
}
|
|
17524
|
+
break;
|
|
17370
17525
|
case "UNARY_OPERATION":
|
|
17371
17526
|
yield* astIterator(ast.operand);
|
|
17372
17527
|
break;
|
|
@@ -17384,6 +17539,11 @@
|
|
|
17384
17539
|
...ast,
|
|
17385
17540
|
args: ast.args.map((child) => mapAst(child, fn)),
|
|
17386
17541
|
};
|
|
17542
|
+
case "ARRAY":
|
|
17543
|
+
return {
|
|
17544
|
+
...ast,
|
|
17545
|
+
value: ast.value.map((row) => row.map((cell) => mapAst(cell, fn))),
|
|
17546
|
+
};
|
|
17387
17547
|
case "UNARY_OPERATION":
|
|
17388
17548
|
return {
|
|
17389
17549
|
...ast,
|
|
@@ -17542,6 +17702,23 @@
|
|
|
17542
17702
|
code.append(...args);
|
|
17543
17703
|
const fnName = ast.value.toUpperCase();
|
|
17544
17704
|
return code.return(`ctx['${fnName}'](${args.map((arg) => arg.returnExpression)})`);
|
|
17705
|
+
case "ARRAY": {
|
|
17706
|
+
// a literal array is compiled into function calls
|
|
17707
|
+
const arrayFunctionCall = {
|
|
17708
|
+
type: "FUNCALL",
|
|
17709
|
+
value: "ARRAY.LITERAL",
|
|
17710
|
+
args: ast.value.map((row) => ({
|
|
17711
|
+
type: "FUNCALL",
|
|
17712
|
+
value: "ARRAY.ROW",
|
|
17713
|
+
args: row,
|
|
17714
|
+
tokenStartIndex: 0,
|
|
17715
|
+
tokenEndIndex: 0,
|
|
17716
|
+
})),
|
|
17717
|
+
tokenStartIndex: 0,
|
|
17718
|
+
tokenEndIndex: 0,
|
|
17719
|
+
};
|
|
17720
|
+
return compileAST(arrayFunctionCall);
|
|
17721
|
+
}
|
|
17545
17722
|
case "UNARY_OPERATION": {
|
|
17546
17723
|
const fnName = UNARY_OPERATOR_MAP[ast.value];
|
|
17547
17724
|
const operand = compileAST(ast.operand, false, false).assignResultToVariable();
|
|
@@ -18821,6 +18998,17 @@
|
|
|
18821
18998
|
return this.colors[id];
|
|
18822
18999
|
}
|
|
18823
19000
|
}
|
|
19001
|
+
const COLORSCHEMES = {
|
|
19002
|
+
greys: ["#ffffff", "#808080", "#000000"],
|
|
19003
|
+
blues: ["#f7fbff", "#6aaed6", "#08306b"],
|
|
19004
|
+
reds: ["#fff5f0", "#fb694a", "#67000d"],
|
|
19005
|
+
greens: ["#f7fcf5", "#73c476", "#00441b"],
|
|
19006
|
+
oranges: ["#fff5eb", "#fd8c3b", "#7f2704"],
|
|
19007
|
+
purples: ["#fcfbfd", "#9e9ac8", "#3f007d"],
|
|
19008
|
+
viridis: ["#440154", "#21918c", "#fde725"],
|
|
19009
|
+
cividis: ["#00224e", "#7d7c78", "#fee838"],
|
|
19010
|
+
rainbow: ["#B41DB4", "#FFFF00", "#00FFFF"],
|
|
19011
|
+
};
|
|
18824
19012
|
/**
|
|
18825
19013
|
* Returns a function that maps a value to a color using a color scale defined by the given
|
|
18826
19014
|
* color/threshold values pairs.
|
|
@@ -25873,6 +26061,17 @@
|
|
|
25873
26061
|
}
|
|
25874
26062
|
}
|
|
25875
26063
|
|
|
26064
|
+
function schemeToColorScale(scheme) {
|
|
26065
|
+
const colors = COLORSCHEMES[scheme];
|
|
26066
|
+
return colors === undefined
|
|
26067
|
+
? undefined
|
|
26068
|
+
: {
|
|
26069
|
+
minColor: colors[0],
|
|
26070
|
+
midColor: colors.length === 3 ? colors[1] : undefined,
|
|
26071
|
+
maxColor: colors[colors.length - 1],
|
|
26072
|
+
};
|
|
26073
|
+
}
|
|
26074
|
+
|
|
25876
26075
|
/**
|
|
25877
26076
|
* parses a formula (as a string) into the same formula,
|
|
25878
26077
|
* but with the references to other cells extracted
|
|
@@ -26516,6 +26715,29 @@
|
|
|
26516
26715
|
}
|
|
26517
26716
|
return data;
|
|
26518
26717
|
},
|
|
26718
|
+
})
|
|
26719
|
+
.add("19.1.0", {
|
|
26720
|
+
migrate(data) {
|
|
26721
|
+
for (const sheet of data.sheets || []) {
|
|
26722
|
+
for (const figure of sheet.figures || []) {
|
|
26723
|
+
if (figure.tag === "chart" && figure.data.type === "geo") {
|
|
26724
|
+
if ("colorScale" in figure.data && typeof figure.data.colorScale === "string") {
|
|
26725
|
+
figure.data.colorScale = schemeToColorScale(figure.data.colorScale);
|
|
26726
|
+
}
|
|
26727
|
+
}
|
|
26728
|
+
if (figure.tag === "carousel") {
|
|
26729
|
+
for (const definition of Object.values(figure.data.chartDefinitions) || []) {
|
|
26730
|
+
if (definition.type === "geo") {
|
|
26731
|
+
if ("colorScale" in definition && typeof definition.colorScale === "string") {
|
|
26732
|
+
definition.colorScale = schemeToColorScale(definition.colorScale);
|
|
26733
|
+
}
|
|
26734
|
+
}
|
|
26735
|
+
}
|
|
26736
|
+
}
|
|
26737
|
+
}
|
|
26738
|
+
}
|
|
26739
|
+
return data;
|
|
26740
|
+
},
|
|
26519
26741
|
});
|
|
26520
26742
|
function fixOverlappingFilters(data) {
|
|
26521
26743
|
for (const sheet of data.sheets || []) {
|
|
@@ -26772,18 +26994,22 @@
|
|
|
26772
26994
|
return messages;
|
|
26773
26995
|
}
|
|
26774
26996
|
function fixChartDefinitions(data, initialMessages) {
|
|
26997
|
+
/**
|
|
26998
|
+
* Revisions created after version 18.5.1 contain the full chart definition in the command
|
|
26999
|
+
* if the data was alreay updated to 18.5.1, then those older revision cannot (by definition) be reaplied
|
|
27000
|
+
* and should not be replayed.
|
|
27001
|
+
* FIXME: every command should be versionned when upgraded to allow finer tuning.
|
|
27002
|
+
*/
|
|
27003
|
+
if (!data.version || compareVersions(String(data.version), "18.5.1") >= 0) {
|
|
27004
|
+
return initialMessages;
|
|
27005
|
+
}
|
|
26775
27006
|
const messages = [];
|
|
26776
27007
|
const map = {};
|
|
26777
27008
|
for (const sheet of data.sheets || []) {
|
|
26778
27009
|
sheet.figures?.forEach((figure) => {
|
|
26779
27010
|
if (figure.tag === "chart") {
|
|
26780
27011
|
// chart definition
|
|
26781
|
-
|
|
26782
|
-
map[figure.data.chartId] = figure.data;
|
|
26783
|
-
}
|
|
26784
|
-
else {
|
|
26785
|
-
map[figure.id] = figure.data;
|
|
26786
|
-
}
|
|
27012
|
+
map[figure.id] = figure.data;
|
|
26787
27013
|
}
|
|
26788
27014
|
});
|
|
26789
27015
|
}
|
|
@@ -27316,22 +27542,34 @@
|
|
|
27316
27542
|
addBorder(sheetId, zone, newBorder, force = false) {
|
|
27317
27543
|
const borders = [];
|
|
27318
27544
|
const plannedBorder = newBorder ? { zone, style: newBorder } : undefined;
|
|
27319
|
-
|
|
27320
|
-
|
|
27321
|
-
|
|
27322
|
-
|
|
27323
|
-
|
|
27545
|
+
// For each side, decide if we must clear the border on the *adjacent*
|
|
27546
|
+
// existing cell when we draw on the opposite side of the new zone.
|
|
27547
|
+
//
|
|
27548
|
+
// Example:
|
|
27549
|
+
// - newBorder.right is set → we draw border on the RIGHT side of `zone`
|
|
27550
|
+
// - the cell on the right may already have a LEFT border on that edge
|
|
27551
|
+
// In that case we clear that LEFT border, so only the new RIGHT border
|
|
27552
|
+
// remains on the shared edge.
|
|
27553
|
+
//
|
|
27554
|
+
// existingBorderSideToClear[side] = true means we should clear the border on that
|
|
27555
|
+
// side of the existing adjacent zone before adding the new border.
|
|
27556
|
+
const existingBorderSideToClear = {
|
|
27557
|
+
left: force || !!newBorder?.right,
|
|
27558
|
+
right: force || !!newBorder?.left,
|
|
27559
|
+
top: force || !!newBorder?.bottom,
|
|
27560
|
+
bottom: force || !!newBorder?.top,
|
|
27324
27561
|
};
|
|
27325
27562
|
let editingZone = [zone];
|
|
27326
27563
|
for (const existingBorder of this.borders[sheetId] ?? []) {
|
|
27327
27564
|
const inter = intersection(existingBorder.zone, zone);
|
|
27328
27565
|
if (!inter) {
|
|
27329
|
-
//
|
|
27566
|
+
// Check if the existing border is adjacent to the new zone
|
|
27330
27567
|
const adjacentEdge = adjacent(existingBorder.zone, zone);
|
|
27331
|
-
if (adjacentEdge &&
|
|
27568
|
+
if (adjacentEdge && existingBorderSideToClear[adjacentEdge.position]) {
|
|
27332
27569
|
for (const newZone of splitIfAdjacent(existingBorder.zone, zone)) {
|
|
27333
27570
|
const border = this.computeBorderFromZone(newZone, existingBorder);
|
|
27334
27571
|
const adjacentEdge = adjacent(newZone, zone);
|
|
27572
|
+
// Clear the existing border on the side that touches the new zone
|
|
27335
27573
|
switch (adjacentEdge?.position) {
|
|
27336
27574
|
case "left":
|
|
27337
27575
|
border.style.left = undefined;
|
|
@@ -29811,7 +30049,8 @@
|
|
|
29811
30049
|
}
|
|
29812
30050
|
break;
|
|
29813
30051
|
case "DUPLICATE_SHEET": {
|
|
29814
|
-
for (const
|
|
30052
|
+
for (const figure of this.getFigures(cmd.sheetId)) {
|
|
30053
|
+
const figureId = figure.id;
|
|
29815
30054
|
const fig = this.figures[cmd.sheetId]?.[figureId];
|
|
29816
30055
|
if (!fig) {
|
|
29817
30056
|
continue;
|
|
@@ -32144,10 +32383,17 @@
|
|
|
32144
32383
|
if (!pivot) {
|
|
32145
32384
|
continue;
|
|
32146
32385
|
}
|
|
32147
|
-
|
|
32386
|
+
const def = deepCopy(pivot.definition);
|
|
32387
|
+
for (const measure of def.measures) {
|
|
32148
32388
|
if (measure.computedBy?.formula === formulaString) {
|
|
32149
|
-
const measureIndex =
|
|
32150
|
-
|
|
32389
|
+
const measureIndex = def.measures.indexOf(measure);
|
|
32390
|
+
if (measureIndex !== -1) {
|
|
32391
|
+
def.measures[measureIndex].computedBy = {
|
|
32392
|
+
formula: newFormulaString,
|
|
32393
|
+
sheetId,
|
|
32394
|
+
};
|
|
32395
|
+
}
|
|
32396
|
+
this.dispatch("UPDATE_PIVOT", { pivotId, pivot: def });
|
|
32151
32397
|
}
|
|
32152
32398
|
}
|
|
32153
32399
|
}
|
|
@@ -33179,6 +33425,9 @@
|
|
|
33179
33425
|
const { sheetId, zone } = definition.dataSet;
|
|
33180
33426
|
const range = this.getters.getRangeFromZone(sheetId, zone);
|
|
33181
33427
|
const adaptedRange = adaptPivotRange(range, applyChange);
|
|
33428
|
+
if (adaptedRange === range) {
|
|
33429
|
+
return;
|
|
33430
|
+
}
|
|
33182
33431
|
const dataSet = adaptedRange && {
|
|
33183
33432
|
sheetId: adaptedRange.sheetId,
|
|
33184
33433
|
zone: adaptedRange.zone,
|
|
@@ -33218,6 +33467,13 @@
|
|
|
33218
33467
|
"getStyleColors",
|
|
33219
33468
|
];
|
|
33220
33469
|
styles = {};
|
|
33470
|
+
allowDispatch(cmd) {
|
|
33471
|
+
switch (cmd.type) {
|
|
33472
|
+
case "SET_FORMATTING":
|
|
33473
|
+
return this.checkUselessSetFormatting(cmd);
|
|
33474
|
+
}
|
|
33475
|
+
return "Success" /* CommandResult.Success */;
|
|
33476
|
+
}
|
|
33221
33477
|
handle(cmd) {
|
|
33222
33478
|
switch (cmd.type) {
|
|
33223
33479
|
case "ADD_MERGE":
|
|
@@ -33442,6 +33698,28 @@
|
|
|
33442
33698
|
exportForExcel(data) {
|
|
33443
33699
|
this.export(data);
|
|
33444
33700
|
}
|
|
33701
|
+
checkUselessSetFormatting(cmd) {
|
|
33702
|
+
const { sheetId, target } = cmd;
|
|
33703
|
+
const hasStyle = "style" in cmd;
|
|
33704
|
+
const hasFormat = "format" in cmd;
|
|
33705
|
+
if (!hasStyle && !hasFormat) {
|
|
33706
|
+
return "NoChanges" /* CommandResult.NoChanges */;
|
|
33707
|
+
}
|
|
33708
|
+
for (const zone of recomputeZones(target)) {
|
|
33709
|
+
for (let col = zone.left; col <= zone.right; col++) {
|
|
33710
|
+
for (let row = zone.top; row <= zone.bottom; row++) {
|
|
33711
|
+
const position = { sheetId, col, row };
|
|
33712
|
+
const cell = this.getters.getCell(position);
|
|
33713
|
+
const style = this.getCellStyle(position);
|
|
33714
|
+
if ((hasStyle && !deepEquals(style, cmd.style)) ||
|
|
33715
|
+
(hasFormat && cell?.format !== cmd.format)) {
|
|
33716
|
+
return "Success" /* CommandResult.Success */;
|
|
33717
|
+
}
|
|
33718
|
+
}
|
|
33719
|
+
}
|
|
33720
|
+
}
|
|
33721
|
+
return "NoChanges" /* CommandResult.NoChanges */;
|
|
33722
|
+
}
|
|
33445
33723
|
}
|
|
33446
33724
|
|
|
33447
33725
|
class TableStylePlugin extends CorePlugin {
|
|
@@ -36469,48 +36747,64 @@
|
|
|
36469
36747
|
}
|
|
36470
36748
|
function getCellContentHeight(ctx, content, style, colSize) {
|
|
36471
36749
|
const maxWidth = style?.wrapping === "wrap" ? colSize - 2 * MIN_CELL_TEXT_MARGIN : undefined;
|
|
36472
|
-
const
|
|
36473
|
-
|
|
36474
|
-
return computeTextLinesHeight(fontSize, numberOfLines) + 2 * PADDING_AUTORESIZE_VERTICAL;
|
|
36750
|
+
const lines = splitTextToWidth(ctx, content, style, maxWidth);
|
|
36751
|
+
return computeMultilineTextSize(ctx, lines, style).height + 2 * PADDING_AUTORESIZE_VERTICAL;
|
|
36475
36752
|
}
|
|
36476
36753
|
function getDefaultContextFont(fontSize, bold = false, italic = false) {
|
|
36477
36754
|
const italicStr = italic ? "italic" : "";
|
|
36478
36755
|
const weight = bold ? "bold" : "";
|
|
36479
36756
|
return `${italicStr} ${weight} ${fontSize}px ${DEFAULT_FONT}`;
|
|
36480
36757
|
}
|
|
36481
|
-
|
|
36482
|
-
|
|
36758
|
+
function computeMultilineTextSize(context, textLines, style = {}, fontUnit = "pt") {
|
|
36759
|
+
if (!textLines.length)
|
|
36760
|
+
return { width: 0, height: 0 };
|
|
36483
36761
|
const font = computeTextFont(style, fontUnit);
|
|
36484
|
-
|
|
36485
|
-
|
|
36486
|
-
|
|
36487
|
-
if (!
|
|
36488
|
-
|
|
36762
|
+
const sizes = textLines.map((line) => computeCachedTextDimension(context, line, font));
|
|
36763
|
+
const height = computeTextLinesHeight(sizes[0].height, textLines.length);
|
|
36764
|
+
const width = Math.max(...sizes.map((size) => size.width));
|
|
36765
|
+
if (!style.rotation) {
|
|
36766
|
+
return { height, width };
|
|
36489
36767
|
}
|
|
36490
|
-
|
|
36491
|
-
|
|
36492
|
-
|
|
36493
|
-
|
|
36494
|
-
|
|
36768
|
+
const cos = Math.abs(Math.cos(style.rotation));
|
|
36769
|
+
const sin = Math.abs(Math.sin(style.rotation));
|
|
36770
|
+
return { width: width * cos + height * sin, height: sin * width + cos * height };
|
|
36771
|
+
}
|
|
36772
|
+
function computeTextWidth(context, text, style = {}, fontUnit = "pt") {
|
|
36773
|
+
const font = computeTextFont(style, fontUnit);
|
|
36774
|
+
return computeCachedTextWidth(context, text, font, style.rotation);
|
|
36775
|
+
}
|
|
36776
|
+
function computeCachedTextWidth(context, text, font, rotation) {
|
|
36777
|
+
const size = computeCachedTextDimension(context, text, font);
|
|
36778
|
+
if (!rotation) {
|
|
36779
|
+
return size.width;
|
|
36495
36780
|
}
|
|
36496
|
-
|
|
36781
|
+
const cos = Math.abs(Math.cos(rotation));
|
|
36782
|
+
const sin = Math.abs(Math.sin(rotation));
|
|
36783
|
+
return size.width * cos + size.height * sin;
|
|
36497
36784
|
}
|
|
36498
36785
|
const textDimensionsCache = {};
|
|
36499
36786
|
function computeTextDimension(context, text, style, fontUnit = "pt") {
|
|
36500
36787
|
const font = computeTextFont(style, fontUnit);
|
|
36501
|
-
context
|
|
36502
|
-
|
|
36503
|
-
|
|
36504
|
-
|
|
36505
|
-
|
|
36506
|
-
|
|
36507
|
-
|
|
36508
|
-
|
|
36788
|
+
const size = computeCachedTextDimension(context, text, font);
|
|
36789
|
+
if (!style.rotation) {
|
|
36790
|
+
return size;
|
|
36791
|
+
}
|
|
36792
|
+
const cos = Math.abs(Math.cos(style.rotation));
|
|
36793
|
+
const sin = Math.abs(Math.sin(style.rotation));
|
|
36794
|
+
return {
|
|
36795
|
+
width: size.width * cos + size.height * sin,
|
|
36796
|
+
height: size.height * cos + size.width * sin,
|
|
36797
|
+
};
|
|
36798
|
+
}
|
|
36799
|
+
function computeCachedTextDimension(context, text, font) {
|
|
36509
36800
|
if (!textDimensionsCache[font]) {
|
|
36510
36801
|
textDimensionsCache[font] = {};
|
|
36511
36802
|
}
|
|
36512
36803
|
if (textDimensionsCache[font][text] === undefined) {
|
|
36804
|
+
context.save();
|
|
36805
|
+
context.font = font;
|
|
36513
36806
|
const measure = context.measureText(text);
|
|
36807
|
+
context.restore();
|
|
36514
36808
|
const width = measure.width;
|
|
36515
36809
|
const height = measure.fontBoundingBoxAscent + measure.fontBoundingBoxDescent;
|
|
36516
36810
|
textDimensionsCache[font][text] = { width, height };
|
|
@@ -38707,7 +39001,8 @@
|
|
|
38707
39001
|
}
|
|
38708
39002
|
break;
|
|
38709
39003
|
case "SET_FORMATTING":
|
|
38710
|
-
if (cmd.style &&
|
|
39004
|
+
if (cmd.style &&
|
|
39005
|
+
("fontSize" in cmd.style || "wrapping" in cmd.style || "rotation" in cmd.style)) {
|
|
38711
39006
|
for (const zone of cmd.target) {
|
|
38712
39007
|
// TODO FLDA use rangeSet
|
|
38713
39008
|
this.updateRowSizeForZoneChange(cmd.sheetId, zone);
|
|
@@ -38864,6 +39159,10 @@
|
|
|
38864
39159
|
? `(${astToFormula(ast.operand)})`
|
|
38865
39160
|
: astToFormula(ast.operand);
|
|
38866
39161
|
return ast.value + rightOperand;
|
|
39162
|
+
case "ARRAY":
|
|
39163
|
+
return ("{" +
|
|
39164
|
+
ast.value.map((row) => row.map((cell) => astToFormula(cell)).join(",")).join(";") +
|
|
39165
|
+
"}");
|
|
38867
39166
|
case "BIN_OPERATION":
|
|
38868
39167
|
const leftOperation = leftOperandNeedsParenthesis(ast)
|
|
38869
39168
|
? `(${astToFormula(ast.left)})`
|
|
@@ -40428,7 +40727,6 @@
|
|
|
40428
40727
|
pivotRegistry.add("SPREADSHEET", {
|
|
40429
40728
|
ui: SpreadsheetPivot,
|
|
40430
40729
|
definition: SpreadsheetPivotRuntimeDefinition,
|
|
40431
|
-
externalData: false,
|
|
40432
40730
|
dateGranularities: [...dateGranularities],
|
|
40433
40731
|
datetimeGranularities: [...dateGranularities, "hour_number", "minute_number", "second_number"],
|
|
40434
40732
|
isMeasureCandidate: (field) => field.type !== "boolean",
|
|
@@ -40470,9 +40768,7 @@
|
|
|
40470
40768
|
handle(cmd) {
|
|
40471
40769
|
if (invalidateEvaluationCommands.has(cmd.type)) {
|
|
40472
40770
|
for (const pivotId of this.getters.getPivotIds()) {
|
|
40473
|
-
|
|
40474
|
-
this.setupPivot(pivotId, { recreate: true });
|
|
40475
|
-
}
|
|
40771
|
+
this.setupPivot(pivotId, { recreate: true });
|
|
40476
40772
|
}
|
|
40477
40773
|
}
|
|
40478
40774
|
switch (cmd.type) {
|
|
@@ -40686,7 +40982,7 @@
|
|
|
40686
40982
|
pivot.init({ reload: true });
|
|
40687
40983
|
}
|
|
40688
40984
|
setupPivot(pivotId, { recreate } = { recreate: false }) {
|
|
40689
|
-
const definition = this.getters.getPivotCoreDefinition(pivotId);
|
|
40985
|
+
const definition = deepCopy(this.getters.getPivotCoreDefinition(pivotId));
|
|
40690
40986
|
if (!(pivotId in this.pivots)) {
|
|
40691
40987
|
const Pivot = withPivotPresentationLayer(pivotRegistry.get(definition.type).ui);
|
|
40692
40988
|
this.pivots[pivotId] = new Pivot(this.custom, { definition, getters: this.getters });
|
|
@@ -43484,6 +43780,7 @@
|
|
|
43484
43780
|
"getTextWidth",
|
|
43485
43781
|
"getCellText",
|
|
43486
43782
|
"getCellMultiLineText",
|
|
43783
|
+
"getMultilineTextSize",
|
|
43487
43784
|
"getContiguousZone",
|
|
43488
43785
|
"computeTextYCoordinate",
|
|
43489
43786
|
];
|
|
@@ -43534,7 +43831,7 @@
|
|
|
43534
43831
|
const content = this.getters.getEvaluatedCell(position).formattedValue;
|
|
43535
43832
|
if (content) {
|
|
43536
43833
|
const multiLineText = splitTextToWidth(this.ctx, content, style, undefined);
|
|
43537
|
-
contentWidth +=
|
|
43834
|
+
contentWidth += computeMultilineTextSize(this.ctx, multiLineText, style).width;
|
|
43538
43835
|
}
|
|
43539
43836
|
for (const icon of this.getters.getCellIcons(position)) {
|
|
43540
43837
|
contentWidth += icon.margin + icon.size;
|
|
@@ -43555,6 +43852,9 @@
|
|
|
43555
43852
|
getTextWidth(text, style) {
|
|
43556
43853
|
return computeTextWidth(this.ctx, text, style);
|
|
43557
43854
|
}
|
|
43855
|
+
getMultilineTextSize(text, style) {
|
|
43856
|
+
return computeMultilineTextSize(this.ctx, text, style);
|
|
43857
|
+
}
|
|
43558
43858
|
getCellText(position, args) {
|
|
43559
43859
|
const cell = this.getters.getCell(position);
|
|
43560
43860
|
const locale = this.getters.getLocale();
|
|
@@ -43753,6 +44053,15 @@
|
|
|
43753
44053
|
return "InvalidFigureId" /* CommandResult.InvalidFigureId */;
|
|
43754
44054
|
}
|
|
43755
44055
|
return "Success" /* CommandResult.Success */;
|
|
44056
|
+
case "DUPLICATE_CAROUSEL_CHART":
|
|
44057
|
+
if (!this.getters.doesCarouselExist(cmd.carouselId) ||
|
|
44058
|
+
!this.getters
|
|
44059
|
+
.getCarousel(cmd.carouselId)
|
|
44060
|
+
.items.some((item) => item.type === "chart" && item.chartId === cmd.chartId) ||
|
|
44061
|
+
this.getters.getChart(cmd.duplicatedChartId)) {
|
|
44062
|
+
return "InvalidFigureId" /* CommandResult.InvalidFigureId */;
|
|
44063
|
+
}
|
|
44064
|
+
return "Success" /* CommandResult.Success */;
|
|
43756
44065
|
case "ADD_NEW_CHART_TO_CAROUSEL":
|
|
43757
44066
|
if (!this.getters.doesCarouselExist(cmd.figureId)) {
|
|
43758
44067
|
return "InvalidFigureId" /* CommandResult.InvalidFigureId */;
|
|
@@ -43777,6 +44086,9 @@
|
|
|
43777
44086
|
case "ADD_FIGURE_CHART_TO_CAROUSEL":
|
|
43778
44087
|
this.addFigureChartToCarousel(cmd.carouselFigureId, cmd.chartFigureId, cmd.sheetId);
|
|
43779
44088
|
break;
|
|
44089
|
+
case "DUPLICATE_CAROUSEL_CHART":
|
|
44090
|
+
this.duplicateCarouselChart(cmd);
|
|
44091
|
+
break;
|
|
43780
44092
|
case "UPDATE_CAROUSEL_ACTIVE_ITEM":
|
|
43781
44093
|
this.carouselStates[cmd.figureId] = this.getCarouselItemId(cmd.item);
|
|
43782
44094
|
break;
|
|
@@ -43915,6 +44227,29 @@
|
|
|
43915
44227
|
});
|
|
43916
44228
|
this.dispatch("DELETE_FIGURE", { sheetId, figureId: chartFigureId });
|
|
43917
44229
|
}
|
|
44230
|
+
duplicateCarouselChart({ carouselId, chartId, sheetId, duplicatedChartId, }) {
|
|
44231
|
+
const chart = this.getters.getChart(chartId);
|
|
44232
|
+
if (!chart) {
|
|
44233
|
+
return;
|
|
44234
|
+
}
|
|
44235
|
+
const carousel = this.getters.getCarousel(carouselId);
|
|
44236
|
+
const duplicatedItemIndex = carousel.items.findIndex((item) => item.type === "chart" && item.chartId === chartId);
|
|
44237
|
+
if (duplicatedItemIndex === -1) {
|
|
44238
|
+
return;
|
|
44239
|
+
}
|
|
44240
|
+
this.dispatch("CREATE_CHART", {
|
|
44241
|
+
chartId: duplicatedChartId,
|
|
44242
|
+
figureId: carouselId,
|
|
44243
|
+
sheetId,
|
|
44244
|
+
definition: chart.getDefinition(),
|
|
44245
|
+
});
|
|
44246
|
+
const carouselItems = insertItemsAtIndex(carousel.items, [{ type: "chart", chartId: duplicatedChartId }], duplicatedItemIndex + 1);
|
|
44247
|
+
this.dispatch("UPDATE_CAROUSEL", {
|
|
44248
|
+
sheetId,
|
|
44249
|
+
figureId: carouselId,
|
|
44250
|
+
definition: { ...carousel, items: carouselItems },
|
|
44251
|
+
});
|
|
44252
|
+
}
|
|
43918
44253
|
getCarouselItemId(item) {
|
|
43919
44254
|
return item.type === "chart" ? item.chartId : "carouselDataView";
|
|
43920
44255
|
}
|
|
@@ -45130,25 +45465,43 @@
|
|
|
45130
45465
|
return "Success" /* CommandResult.Success */;
|
|
45131
45466
|
}
|
|
45132
45467
|
handleEvent(event) {
|
|
45133
|
-
|
|
45134
|
-
let zones = [];
|
|
45468
|
+
let anchor = event.anchor;
|
|
45469
|
+
let zones = [...this.gridSelection.zones];
|
|
45135
45470
|
this.isUnbounded = event.options?.unbounded || false;
|
|
45136
45471
|
switch (event.mode) {
|
|
45137
45472
|
case "overrideSelection":
|
|
45138
45473
|
zones = [anchor.zone];
|
|
45139
45474
|
break;
|
|
45140
45475
|
case "updateAnchor":
|
|
45141
|
-
zones = [...this.gridSelection.zones];
|
|
45142
45476
|
const index = zones.findIndex((z) => isEqual(z, event.previousAnchor.zone));
|
|
45143
45477
|
if (index >= 0) {
|
|
45144
45478
|
zones[index] = anchor.zone;
|
|
45145
45479
|
}
|
|
45146
45480
|
break;
|
|
45147
45481
|
case "newAnchor":
|
|
45148
|
-
zones
|
|
45482
|
+
zones.push(anchor.zone);
|
|
45483
|
+
break;
|
|
45484
|
+
case "commitSelection":
|
|
45485
|
+
const zoneToSplit = zones.find((zone) => isZoneInside(anchor.zone, zone) && !isEqual(anchor.zone, zone));
|
|
45486
|
+
const removeFullAnchor = zones.filter((zone) => isEqual(anchor.zone, zone)).length > 1;
|
|
45487
|
+
if (removeFullAnchor && zones.length > 2) {
|
|
45488
|
+
zones = zones.filter((zone) => !isEqual(zone, anchor.zone));
|
|
45489
|
+
}
|
|
45490
|
+
else if (zoneToSplit) {
|
|
45491
|
+
const splittedZones = splitZone(anchor.zone, zoneToSplit);
|
|
45492
|
+
zones = zones
|
|
45493
|
+
.filter((z) => !isEqual(z, anchor.zone) && !isEqual(z, zoneToSplit))
|
|
45494
|
+
.concat(splittedZones);
|
|
45495
|
+
}
|
|
45496
|
+
zones = uniqueZones(zones);
|
|
45497
|
+
const lastZone = zones[zones.length - 1];
|
|
45498
|
+
anchor = {
|
|
45499
|
+
cell: { col: lastZone.left, row: lastZone.top },
|
|
45500
|
+
zone: lastZone,
|
|
45501
|
+
};
|
|
45149
45502
|
break;
|
|
45150
45503
|
}
|
|
45151
|
-
this.setSelectionMixin(
|
|
45504
|
+
this.setSelectionMixin(anchor, zones);
|
|
45152
45505
|
/** Any change to the selection has to be reflected in the selection processor. */
|
|
45153
45506
|
this.selection.resetDefaultAnchor(this, deepCopy(this.gridSelection.anchor));
|
|
45154
45507
|
const { col, row } = this.gridSelection.anchor.cell;
|
|
@@ -45428,7 +45781,7 @@
|
|
|
45428
45781
|
setSelectionMixin(anchor, zones) {
|
|
45429
45782
|
const { anchor: clippedAnchor, zones: clippedZones } = this.clipSelection(this.getters.getActiveSheetId(), { anchor, zones });
|
|
45430
45783
|
this.gridSelection.anchor = clippedAnchor;
|
|
45431
|
-
this.gridSelection.zones =
|
|
45784
|
+
this.gridSelection.zones = clippedZones;
|
|
45432
45785
|
}
|
|
45433
45786
|
/**
|
|
45434
45787
|
* Change the anchor of the selection active cell to an absolute col and row index.
|
|
@@ -46138,6 +46491,7 @@
|
|
|
46138
46491
|
"getGridOffset",
|
|
46139
46492
|
"getViewportZoomLevel",
|
|
46140
46493
|
"getScrollBarWidth",
|
|
46494
|
+
"getMaximumSheetOffset",
|
|
46141
46495
|
];
|
|
46142
46496
|
viewports = {};
|
|
46143
46497
|
/**
|
|
@@ -47243,6 +47597,9 @@
|
|
|
47243
47597
|
observe(owner, callbacks) {
|
|
47244
47598
|
this.observers.set(owner, { owner, callbacks });
|
|
47245
47599
|
}
|
|
47600
|
+
unobserve(owner) {
|
|
47601
|
+
this.observers.delete(owner);
|
|
47602
|
+
}
|
|
47246
47603
|
/**
|
|
47247
47604
|
* Capture the stream for yourself
|
|
47248
47605
|
*/
|
|
@@ -47335,6 +47692,9 @@
|
|
|
47335
47692
|
observe(owner, callbacks) {
|
|
47336
47693
|
this.stream.observe(owner, callbacks);
|
|
47337
47694
|
}
|
|
47695
|
+
unobserve(owner) {
|
|
47696
|
+
this.stream.unobserve(owner);
|
|
47697
|
+
}
|
|
47338
47698
|
release(owner) {
|
|
47339
47699
|
if (this.stream.isListening(owner)) {
|
|
47340
47700
|
this.stream.release(owner);
|
|
@@ -47393,6 +47753,9 @@
|
|
|
47393
47753
|
bottom: Math.max(anchorRow, row),
|
|
47394
47754
|
};
|
|
47395
47755
|
const expandedZone = this.getters.expandZone(sheetId, zone);
|
|
47756
|
+
if (isEqual(this.anchor.zone, expandedZone)) {
|
|
47757
|
+
return new DispatchResult("NoChanges" /* CommandResult.NoChanges */);
|
|
47758
|
+
}
|
|
47396
47759
|
const anchor = { zone: expandedZone, cell: { col: anchorCol, row: anchorRow } };
|
|
47397
47760
|
return this.processEvent({
|
|
47398
47761
|
mode: "updateAnchor",
|
|
@@ -47413,6 +47776,22 @@
|
|
|
47413
47776
|
mode: "newAnchor",
|
|
47414
47777
|
});
|
|
47415
47778
|
}
|
|
47779
|
+
/**
|
|
47780
|
+
* Triggered on mouse up to finalize the selection.
|
|
47781
|
+
* - If the current anchor zone already exists in the selection, it will be removed.
|
|
47782
|
+
* - If the anchor zone overlaps with existing zones, it will be split into
|
|
47783
|
+
* multiple non-overlapping parts.
|
|
47784
|
+
*/
|
|
47785
|
+
commitSelection() {
|
|
47786
|
+
return this.processEvent({
|
|
47787
|
+
options: {
|
|
47788
|
+
scrollIntoView: false,
|
|
47789
|
+
unbounded: true,
|
|
47790
|
+
},
|
|
47791
|
+
anchor: this.anchor,
|
|
47792
|
+
mode: "commitSelection",
|
|
47793
|
+
});
|
|
47794
|
+
}
|
|
47416
47795
|
/**
|
|
47417
47796
|
* Increase or decrease the size of the current anchor zone.
|
|
47418
47797
|
* The anchor cell remains where it is. It's the opposite side
|
|
@@ -50927,8 +51306,8 @@
|
|
|
50927
51306
|
|
|
50928
51307
|
|
|
50929
51308
|
__info__.version = "19.1.0-alpha.3";
|
|
50930
|
-
__info__.date = "2025-
|
|
50931
|
-
__info__.hash = "
|
|
51309
|
+
__info__.date = "2025-12-02T05:34:07.213Z";
|
|
51310
|
+
__info__.hash = "04cf666";
|
|
50932
51311
|
|
|
50933
51312
|
|
|
50934
51313
|
})(this.o_spreadsheet_engine = this.o_spreadsheet_engine || {});
|