@odoo/o-spreadsheet 16.4.0-alpha.7 → 16.5.0-alpha.0
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 +684 -475
- package/dist/o-spreadsheet.d.ts +140 -110
- package/dist/o-spreadsheet.esm.js +684 -475
- package/dist/o-spreadsheet.iife.js +684 -475
- package/dist/o-spreadsheet.iife.min.js +271 -267
- package/package.json +11 -11
|
@@ -235,6 +235,7 @@ const DEFAULT_FONT_SIZE = 10;
|
|
|
235
235
|
const HEADER_FONT_SIZE = 11;
|
|
236
236
|
const DEFAULT_FONT = "'Roboto', arial";
|
|
237
237
|
const DEFAULT_VERTICAL_ALIGN = "bottom";
|
|
238
|
+
const DEFAULT_WRAPPING_MODE = "overflow";
|
|
238
239
|
// Borders
|
|
239
240
|
const DEFAULT_BORDER_DESC = { style: "thin", color: "#000000" };
|
|
240
241
|
const DEFAULT_FILTER_BORDER_DESC = { style: "thin", color: FILTERS_COLOR };
|
|
@@ -392,82 +393,6 @@ function getCanonicalSheetName(sheetName) {
|
|
|
392
393
|
function clip(val, min, max) {
|
|
393
394
|
return val < min ? min : val > max ? max : val;
|
|
394
395
|
}
|
|
395
|
-
function computeTextLinesHeight(textLineHeight, numberOfLines = 1) {
|
|
396
|
-
return numberOfLines * (textLineHeight + MIN_CELL_TEXT_MARGIN) - MIN_CELL_TEXT_MARGIN;
|
|
397
|
-
}
|
|
398
|
-
/**
|
|
399
|
-
* Get the default height of the cell given its style.
|
|
400
|
-
*/
|
|
401
|
-
function getDefaultCellHeight(cell) {
|
|
402
|
-
if (!cell || !cell.content) {
|
|
403
|
-
return DEFAULT_CELL_HEIGHT;
|
|
404
|
-
}
|
|
405
|
-
const fontSize = computeTextFontSizeInPixels(cell.style);
|
|
406
|
-
// the number of lines should be computed from the formula result, but it's not evaluated at this point
|
|
407
|
-
const numberOfLines = cell.isFormula ? 1 : cell.content.split(NEWLINE).length;
|
|
408
|
-
return computeTextLinesHeight(fontSize, numberOfLines) + 2 * PADDING_AUTORESIZE_VERTICAL;
|
|
409
|
-
}
|
|
410
|
-
function computeTextWidth(context, text, style) {
|
|
411
|
-
const font = computeTextFont(style);
|
|
412
|
-
if (!textWidthCache[font]) {
|
|
413
|
-
textWidthCache[font] = {};
|
|
414
|
-
}
|
|
415
|
-
if (textWidthCache[font][text] === undefined) {
|
|
416
|
-
context.save();
|
|
417
|
-
context.font = font;
|
|
418
|
-
const textWidth = context.measureText(text).width;
|
|
419
|
-
context.restore();
|
|
420
|
-
textWidthCache[font][text] = textWidth;
|
|
421
|
-
}
|
|
422
|
-
return textWidthCache[font][text];
|
|
423
|
-
}
|
|
424
|
-
const textWidthCache = {};
|
|
425
|
-
function fontSizeInPixels(fontSize) {
|
|
426
|
-
return Math.round((fontSize * 96) / 72);
|
|
427
|
-
}
|
|
428
|
-
function computeTextFont(style) {
|
|
429
|
-
const italic = style.italic ? "italic " : "";
|
|
430
|
-
const weight = style.bold ? "bold" : DEFAULT_FONT_WEIGHT;
|
|
431
|
-
const size = computeTextFontSizeInPixels(style);
|
|
432
|
-
return `${italic}${weight} ${size}px ${DEFAULT_FONT}`;
|
|
433
|
-
}
|
|
434
|
-
function computeTextFontSizeInPixels(style) {
|
|
435
|
-
const sizeInPt = style?.fontSize || DEFAULT_FONT_SIZE;
|
|
436
|
-
return fontSizeInPixels(sizeInPt);
|
|
437
|
-
}
|
|
438
|
-
/**
|
|
439
|
-
* Return the font size that makes the width of a text match the given line width.
|
|
440
|
-
* Minimum font size is 1.
|
|
441
|
-
*
|
|
442
|
-
* @param getTextWidth function that takes a fontSize as argument, and return the width of the text with this font size.
|
|
443
|
-
*/
|
|
444
|
-
function getFontSizeMatchingWidth(lineWidth, maxFontSize, getTextWidth, precision = 0.25) {
|
|
445
|
-
let minFontSize = 1;
|
|
446
|
-
if (getTextWidth(minFontSize) > lineWidth)
|
|
447
|
-
return minFontSize;
|
|
448
|
-
if (getTextWidth(maxFontSize) < lineWidth)
|
|
449
|
-
return maxFontSize;
|
|
450
|
-
// Dichotomic search
|
|
451
|
-
let fontSize = (minFontSize + maxFontSize) / 2;
|
|
452
|
-
let currentTextWidth = getTextWidth(fontSize);
|
|
453
|
-
// Use a maximum number of iterations to be safe, because measuring text isn't 100% precise
|
|
454
|
-
let iterations = 0;
|
|
455
|
-
while (Math.abs(currentTextWidth - lineWidth) > precision && iterations < 20) {
|
|
456
|
-
if (currentTextWidth >= lineWidth) {
|
|
457
|
-
maxFontSize = (minFontSize + maxFontSize) / 2;
|
|
458
|
-
}
|
|
459
|
-
else {
|
|
460
|
-
minFontSize = (minFontSize + maxFontSize) / 2;
|
|
461
|
-
}
|
|
462
|
-
fontSize = (minFontSize + maxFontSize) / 2;
|
|
463
|
-
currentTextWidth = getTextWidth(fontSize);
|
|
464
|
-
iterations++;
|
|
465
|
-
}
|
|
466
|
-
return fontSize;
|
|
467
|
-
}
|
|
468
|
-
function computeIconWidth(style) {
|
|
469
|
-
return computeTextFontSizeInPixels(style) + 2 * MIN_CF_ICON_MARGIN;
|
|
470
|
-
}
|
|
471
396
|
/**
|
|
472
397
|
* Create a range from start (included) to end (excluded).
|
|
473
398
|
* range(10, 13) => [10, 11, 12]
|
|
@@ -722,10 +647,6 @@ function removeFalsyAttributes(obj) {
|
|
|
722
647
|
Object.keys(cleanObject).forEach((key) => !cleanObject[key] && delete cleanObject[key]);
|
|
723
648
|
return cleanObject;
|
|
724
649
|
}
|
|
725
|
-
/** Transform a string to lower case. If the string is undefined, return an empty string */
|
|
726
|
-
function toLowerCase(str) {
|
|
727
|
-
return str ? str.toLowerCase() : "";
|
|
728
|
-
}
|
|
729
650
|
function transpose2dArray(matrix, callback = (val) => val) {
|
|
730
651
|
if (!matrix.length)
|
|
731
652
|
return [];
|
|
@@ -814,6 +735,14 @@ function memoize(func) {
|
|
|
814
735
|
return cache.get(args[0]);
|
|
815
736
|
},
|
|
816
737
|
}[funcName];
|
|
738
|
+
}
|
|
739
|
+
function removeIndexesFromArray(array, indexes) {
|
|
740
|
+
return array.filter((_, index) => !indexes.includes(index));
|
|
741
|
+
}
|
|
742
|
+
function insertItemsAtIndex(array, items, index) {
|
|
743
|
+
const newArray = [...array];
|
|
744
|
+
newArray.splice(index, 0, ...items);
|
|
745
|
+
return newArray;
|
|
817
746
|
}
|
|
818
747
|
|
|
819
748
|
const RBA_REGEX = /rgba?\(|\s+|\)/gi;
|
|
@@ -957,13 +886,13 @@ function rgbaToHex(rgba) {
|
|
|
957
886
|
let g = rgba.g.toString(16);
|
|
958
887
|
let b = rgba.b.toString(16);
|
|
959
888
|
let a = Math.round(rgba.a * 255).toString(16);
|
|
960
|
-
if (r.length
|
|
889
|
+
if (r.length === 1)
|
|
961
890
|
r = "0" + r;
|
|
962
|
-
if (g.length
|
|
891
|
+
if (g.length === 1)
|
|
963
892
|
g = "0" + g;
|
|
964
|
-
if (b.length
|
|
893
|
+
if (b.length === 1)
|
|
965
894
|
b = "0" + b;
|
|
966
|
-
if (a.length
|
|
895
|
+
if (a.length === 1)
|
|
967
896
|
a = "0" + a;
|
|
968
897
|
if (a === "ff")
|
|
969
898
|
a = "";
|
|
@@ -1066,13 +995,13 @@ function rgbaToHSLA(rgba) {
|
|
|
1066
995
|
let l = 0;
|
|
1067
996
|
// Calculate hue
|
|
1068
997
|
// No difference
|
|
1069
|
-
if (delta
|
|
998
|
+
if (delta === 0)
|
|
1070
999
|
h = 0;
|
|
1071
1000
|
// Red is max
|
|
1072
|
-
else if (cMax
|
|
1001
|
+
else if (cMax === r)
|
|
1073
1002
|
h = ((g - b) / delta) % 6;
|
|
1074
1003
|
// Green is max
|
|
1075
|
-
else if (cMax
|
|
1004
|
+
else if (cMax === g)
|
|
1076
1005
|
h = (b - r) / delta + 2;
|
|
1077
1006
|
// Blue is max
|
|
1078
1007
|
else
|
|
@@ -1083,7 +1012,7 @@ function rgbaToHSLA(rgba) {
|
|
|
1083
1012
|
h += 360;
|
|
1084
1013
|
l = (cMax + cMin) / 2;
|
|
1085
1014
|
// Calculate saturation
|
|
1086
|
-
s = delta
|
|
1015
|
+
s = delta === 0 ? 0 : delta / (1 - Math.abs(2 * l - 1));
|
|
1087
1016
|
// Multiply l and s by 100
|
|
1088
1017
|
s = +(s * 100).toFixed(1);
|
|
1089
1018
|
l = +(l * 100).toFixed(1);
|
|
@@ -1520,7 +1449,7 @@ function addMonthsToDate(date, months, keepEndOfMonth) {
|
|
|
1520
1449
|
}
|
|
1521
1450
|
function isLeapYear(year) {
|
|
1522
1451
|
const _year = Math.trunc(year);
|
|
1523
|
-
return (_year % 4 === 0 && _year % 100 != 0) || _year % 400
|
|
1452
|
+
return (_year % 4 === 0 && _year % 100 != 0) || _year % 400 === 0;
|
|
1524
1453
|
}
|
|
1525
1454
|
function getYearFrac(startDate, endDate, _dayCountConvention) {
|
|
1526
1455
|
if (startDate === endDate) {
|
|
@@ -2181,6 +2110,39 @@ function detectNumberFormat(content) {
|
|
|
2181
2110
|
}
|
|
2182
2111
|
return undefined;
|
|
2183
2112
|
}
|
|
2113
|
+
function createCurrencyFormat(currency) {
|
|
2114
|
+
const decimalPlaces = currency.decimalPlaces ?? 2;
|
|
2115
|
+
const position = currency.position ?? "before";
|
|
2116
|
+
const code = currency.code ?? "";
|
|
2117
|
+
const symbol = currency.symbol ?? "";
|
|
2118
|
+
const decimalRepresentation = decimalPlaces ? "." + "0".repeat(decimalPlaces) : "";
|
|
2119
|
+
const numberFormat = "#,##0" + decimalRepresentation;
|
|
2120
|
+
let textExpression = `${code} ${symbol}`.trim();
|
|
2121
|
+
if (position === "after" && code) {
|
|
2122
|
+
textExpression = " " + textExpression;
|
|
2123
|
+
}
|
|
2124
|
+
return insertTextInFormat(textExpression, position, numberFormat);
|
|
2125
|
+
}
|
|
2126
|
+
function insertTextInFormat(text, position, format) {
|
|
2127
|
+
const textExpression = `[$${text}]`;
|
|
2128
|
+
return position === "before" ? textExpression + format : format + textExpression;
|
|
2129
|
+
}
|
|
2130
|
+
function roundFormat(format) {
|
|
2131
|
+
const internalFormat = parseFormat(format);
|
|
2132
|
+
const roundedFormat = internalFormat.map((formatPart) => {
|
|
2133
|
+
if (formatPart.type === "NUMBER") {
|
|
2134
|
+
return {
|
|
2135
|
+
type: formatPart.type,
|
|
2136
|
+
format: {
|
|
2137
|
+
...formatPart.format,
|
|
2138
|
+
decimalPart: undefined,
|
|
2139
|
+
},
|
|
2140
|
+
};
|
|
2141
|
+
}
|
|
2142
|
+
return formatPart;
|
|
2143
|
+
});
|
|
2144
|
+
return convertInternalFormatToFormat(roundedFormat);
|
|
2145
|
+
}
|
|
2184
2146
|
function createLargeNumberFormat(format, magnitude, postFix, locale) {
|
|
2185
2147
|
const internalFormat = parseFormat(format || "#,##0");
|
|
2186
2148
|
const largeNumberFormat = internalFormat
|
|
@@ -3274,6 +3236,169 @@ function createDefaultRows(rowNumber) {
|
|
|
3274
3236
|
return rows;
|
|
3275
3237
|
}
|
|
3276
3238
|
|
|
3239
|
+
function computeTextLinesHeight(textLineHeight, numberOfLines = 1) {
|
|
3240
|
+
return numberOfLines * (textLineHeight + MIN_CELL_TEXT_MARGIN) - MIN_CELL_TEXT_MARGIN;
|
|
3241
|
+
}
|
|
3242
|
+
/**
|
|
3243
|
+
* Get the default height of the cell given its style.
|
|
3244
|
+
*/
|
|
3245
|
+
function getDefaultCellHeight(ctx, cell, colSize) {
|
|
3246
|
+
if (!cell || !cell.content)
|
|
3247
|
+
return DEFAULT_CELL_HEIGHT;
|
|
3248
|
+
const maxWidth = cell.style?.wrapping ? colSize - 2 * MIN_CELL_TEXT_MARGIN : undefined;
|
|
3249
|
+
const numberOfLines = cell.isFormula
|
|
3250
|
+
? 1
|
|
3251
|
+
: splitTextToWidth(ctx, cell.content, cell.style, maxWidth).length;
|
|
3252
|
+
const fontSize = computeTextFontSizeInPixels(cell.style);
|
|
3253
|
+
return computeTextLinesHeight(fontSize, numberOfLines) + 2 * PADDING_AUTORESIZE_VERTICAL;
|
|
3254
|
+
}
|
|
3255
|
+
const textWidthCache = {};
|
|
3256
|
+
function computeTextWidth(context, text, style) {
|
|
3257
|
+
const font = computeTextFont(style);
|
|
3258
|
+
if (!textWidthCache[font]) {
|
|
3259
|
+
textWidthCache[font] = {};
|
|
3260
|
+
}
|
|
3261
|
+
if (textWidthCache[font][text] === undefined) {
|
|
3262
|
+
context.save();
|
|
3263
|
+
context.font = font;
|
|
3264
|
+
const textWidth = context.measureText(text).width;
|
|
3265
|
+
context.restore();
|
|
3266
|
+
textWidthCache[font][text] = textWidth;
|
|
3267
|
+
}
|
|
3268
|
+
return textWidthCache[font][text];
|
|
3269
|
+
}
|
|
3270
|
+
function fontSizeInPixels(fontSize) {
|
|
3271
|
+
return Math.round((fontSize * 96) / 72);
|
|
3272
|
+
}
|
|
3273
|
+
function computeTextFont(style) {
|
|
3274
|
+
const italic = style.italic ? "italic " : "";
|
|
3275
|
+
const weight = style.bold ? "bold" : DEFAULT_FONT_WEIGHT;
|
|
3276
|
+
const size = computeTextFontSizeInPixels(style);
|
|
3277
|
+
return `${italic}${weight} ${size}px ${DEFAULT_FONT}`;
|
|
3278
|
+
}
|
|
3279
|
+
function computeTextFontSizeInPixels(style) {
|
|
3280
|
+
const sizeInPt = style?.fontSize || DEFAULT_FONT_SIZE;
|
|
3281
|
+
return fontSizeInPixels(sizeInPt);
|
|
3282
|
+
}
|
|
3283
|
+
function splitWordToSpecificWidth(ctx, word, width, style) {
|
|
3284
|
+
const wordWidth = computeTextWidth(ctx, word, style);
|
|
3285
|
+
if (wordWidth <= width) {
|
|
3286
|
+
return [word];
|
|
3287
|
+
}
|
|
3288
|
+
const splitWord = [];
|
|
3289
|
+
let wordPart = "";
|
|
3290
|
+
for (let l of word) {
|
|
3291
|
+
const wordPartWidth = computeTextWidth(ctx, wordPart + l, style);
|
|
3292
|
+
if (wordPartWidth > width) {
|
|
3293
|
+
splitWord.push(wordPart);
|
|
3294
|
+
wordPart = l;
|
|
3295
|
+
}
|
|
3296
|
+
else {
|
|
3297
|
+
wordPart += l;
|
|
3298
|
+
}
|
|
3299
|
+
}
|
|
3300
|
+
splitWord.push(wordPart);
|
|
3301
|
+
return splitWord;
|
|
3302
|
+
}
|
|
3303
|
+
/**
|
|
3304
|
+
* Return the given text, split in multiple lines if needed. The text will be split in multiple
|
|
3305
|
+
* line if it contains NEWLINE characters, or if it's longer than the given width.
|
|
3306
|
+
*/
|
|
3307
|
+
function splitTextToWidth(ctx, text, style, width) {
|
|
3308
|
+
if (!style)
|
|
3309
|
+
style = {};
|
|
3310
|
+
const brokenText = [];
|
|
3311
|
+
// Checking if text contains NEWLINE before split makes it very slightly slower if text contains it,
|
|
3312
|
+
// but 5-10x faster if it doesn't
|
|
3313
|
+
const lines = text.includes(NEWLINE) ? text.split(NEWLINE) : [text];
|
|
3314
|
+
for (const line of lines) {
|
|
3315
|
+
const words = line.includes(" ") ? line.split(" ") : [line];
|
|
3316
|
+
if (!width) {
|
|
3317
|
+
brokenText.push(line);
|
|
3318
|
+
continue;
|
|
3319
|
+
}
|
|
3320
|
+
let textLine = "";
|
|
3321
|
+
let availableWidth = width;
|
|
3322
|
+
for (let word of words) {
|
|
3323
|
+
const splitWord = splitWordToSpecificWidth(ctx, word, width, style);
|
|
3324
|
+
const lastPart = splitWord.pop();
|
|
3325
|
+
const lastPartWidth = computeTextWidth(ctx, lastPart, style);
|
|
3326
|
+
// At this step: "splitWord" is an array composed of parts of word whose
|
|
3327
|
+
// length is at most equal to "width".
|
|
3328
|
+
// Last part contains the end of the word.
|
|
3329
|
+
// Note that: When word length is less than width, then lastPart is equal
|
|
3330
|
+
// to word and splitWord is empty
|
|
3331
|
+
if (splitWord.length) {
|
|
3332
|
+
if (textLine !== "") {
|
|
3333
|
+
brokenText.push(textLine);
|
|
3334
|
+
textLine = "";
|
|
3335
|
+
availableWidth = width;
|
|
3336
|
+
}
|
|
3337
|
+
splitWord.forEach((wordPart) => {
|
|
3338
|
+
brokenText.push(wordPart);
|
|
3339
|
+
});
|
|
3340
|
+
textLine = lastPart;
|
|
3341
|
+
availableWidth = width - lastPartWidth;
|
|
3342
|
+
}
|
|
3343
|
+
else {
|
|
3344
|
+
// here "lastPart" is equal to "word" and the "word" size is smaller than "width"
|
|
3345
|
+
const _word = textLine === "" ? lastPart : " " + lastPart;
|
|
3346
|
+
const wordWidth = computeTextWidth(ctx, _word, style);
|
|
3347
|
+
if (wordWidth <= availableWidth) {
|
|
3348
|
+
textLine += _word;
|
|
3349
|
+
availableWidth -= wordWidth;
|
|
3350
|
+
}
|
|
3351
|
+
else {
|
|
3352
|
+
brokenText.push(textLine);
|
|
3353
|
+
textLine = lastPart;
|
|
3354
|
+
availableWidth = width - lastPartWidth;
|
|
3355
|
+
}
|
|
3356
|
+
}
|
|
3357
|
+
}
|
|
3358
|
+
if (textLine !== "") {
|
|
3359
|
+
brokenText.push(textLine);
|
|
3360
|
+
}
|
|
3361
|
+
}
|
|
3362
|
+
return brokenText;
|
|
3363
|
+
}
|
|
3364
|
+
/**
|
|
3365
|
+
* Return the font size that makes the width of a text match the given line width.
|
|
3366
|
+
* Minimum font size is 1.
|
|
3367
|
+
*
|
|
3368
|
+
* @param getTextWidth function that takes a fontSize as argument, and return the width of the text with this font size.
|
|
3369
|
+
*/
|
|
3370
|
+
function getFontSizeMatchingWidth(lineWidth, maxFontSize, getTextWidth, precision = 0.25) {
|
|
3371
|
+
let minFontSize = 1;
|
|
3372
|
+
if (getTextWidth(minFontSize) > lineWidth)
|
|
3373
|
+
return minFontSize;
|
|
3374
|
+
if (getTextWidth(maxFontSize) < lineWidth)
|
|
3375
|
+
return maxFontSize;
|
|
3376
|
+
// Dichotomic search
|
|
3377
|
+
let fontSize = (minFontSize + maxFontSize) / 2;
|
|
3378
|
+
let currentTextWidth = getTextWidth(fontSize);
|
|
3379
|
+
// Use a maximum number of iterations to be safe, because measuring text isn't 100% precise
|
|
3380
|
+
let iterations = 0;
|
|
3381
|
+
while (Math.abs(currentTextWidth - lineWidth) > precision && iterations < 20) {
|
|
3382
|
+
if (currentTextWidth >= lineWidth) {
|
|
3383
|
+
maxFontSize = (minFontSize + maxFontSize) / 2;
|
|
3384
|
+
}
|
|
3385
|
+
else {
|
|
3386
|
+
minFontSize = (minFontSize + maxFontSize) / 2;
|
|
3387
|
+
}
|
|
3388
|
+
fontSize = (minFontSize + maxFontSize) / 2;
|
|
3389
|
+
currentTextWidth = getTextWidth(fontSize);
|
|
3390
|
+
iterations++;
|
|
3391
|
+
}
|
|
3392
|
+
return fontSize;
|
|
3393
|
+
}
|
|
3394
|
+
function computeIconWidth(style) {
|
|
3395
|
+
return computeTextFontSizeInPixels(style) + 2 * MIN_CF_ICON_MARGIN;
|
|
3396
|
+
}
|
|
3397
|
+
/** Transform a string to lower case. If the string is undefined, return an empty string */
|
|
3398
|
+
function toLowerCase(str) {
|
|
3399
|
+
return str ? str.toLowerCase() : "";
|
|
3400
|
+
}
|
|
3401
|
+
|
|
3277
3402
|
/*
|
|
3278
3403
|
* https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript
|
|
3279
3404
|
* */
|
|
@@ -3296,7 +3421,7 @@ class UuidGenerator {
|
|
|
3296
3421
|
else {
|
|
3297
3422
|
// mainly for jest and other browsers that do not have the crypto functionality
|
|
3298
3423
|
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
|
|
3299
|
-
var r = (Math.random() * 16) | 0, v = c
|
|
3424
|
+
var r = (Math.random() * 16) | 0, v = c === "x" ? r : (r & 0x3) | 0x8;
|
|
3300
3425
|
return v.toString(16);
|
|
3301
3426
|
});
|
|
3302
3427
|
}
|
|
@@ -4124,6 +4249,7 @@ var CommandResult;
|
|
|
4124
4249
|
CommandResult[CommandResult["NoSplitSeparatorInSelection"] = 92] = "NoSplitSeparatorInSelection";
|
|
4125
4250
|
CommandResult[CommandResult["NoActiveSheet"] = 93] = "NoActiveSheet";
|
|
4126
4251
|
CommandResult[CommandResult["InvalidLocale"] = 94] = "InvalidLocale";
|
|
4252
|
+
CommandResult[CommandResult["AlreadyInPaintingFormatMode"] = 95] = "AlreadyInPaintingFormatMode";
|
|
4127
4253
|
})(CommandResult || (CommandResult = {}));
|
|
4128
4254
|
|
|
4129
4255
|
const borderStyles = ["thin", "medium", "thick", "dashed", "dotted"];
|
|
@@ -5939,8 +6065,8 @@ class Menu extends Component {
|
|
|
5939
6065
|
return this.props.menuItems.some((menuItem) => !!menuItem.icon || !!menuItem.isActive);
|
|
5940
6066
|
}
|
|
5941
6067
|
getIconName(menu) {
|
|
5942
|
-
if (menu.icon) {
|
|
5943
|
-
return menu.icon;
|
|
6068
|
+
if (menu.icon(this.env)) {
|
|
6069
|
+
return menu.icon(this.env);
|
|
5944
6070
|
}
|
|
5945
6071
|
if (menu.isActive?.(this.env)) {
|
|
5946
6072
|
return "o-spreadsheet-Icon.CHECK";
|
|
@@ -6374,7 +6500,7 @@ function invertMatrix(M) {
|
|
|
6374
6500
|
for (let pivot = 0; pivot < dim; pivot++) {
|
|
6375
6501
|
let diagonalElement = C[pivot][pivot];
|
|
6376
6502
|
// if we have a 0 on the diagonal we'll need to swap with a lower row
|
|
6377
|
-
if (diagonalElement
|
|
6503
|
+
if (diagonalElement === 0) {
|
|
6378
6504
|
//look through every row below the i'th row
|
|
6379
6505
|
for (let row = pivot + 1; row < dim; row++) {
|
|
6380
6506
|
//if the ii'th row has a non-0 in the i'th col, swap it with that row
|
|
@@ -6401,7 +6527,7 @@ function invertMatrix(M) {
|
|
|
6401
6527
|
// the other rows so that there will be 0's in this column in the
|
|
6402
6528
|
// rows above and below this one
|
|
6403
6529
|
for (let row = 0; row < dim; row++) {
|
|
6404
|
-
if (row
|
|
6530
|
+
if (row === pivot) {
|
|
6405
6531
|
continue;
|
|
6406
6532
|
}
|
|
6407
6533
|
// We want to change this element to 0
|
|
@@ -12466,7 +12592,7 @@ const ISNA = {
|
|
|
12466
12592
|
return false;
|
|
12467
12593
|
}
|
|
12468
12594
|
catch (e) {
|
|
12469
|
-
return e?.errorType
|
|
12595
|
+
return e?.errorType === CellErrorType.NotAvailable;
|
|
12470
12596
|
}
|
|
12471
12597
|
},
|
|
12472
12598
|
isExported: true,
|
|
@@ -15182,6 +15308,8 @@ const uuidGenerator$2 = new UuidGenerator();
|
|
|
15182
15308
|
function createAction(item) {
|
|
15183
15309
|
const name = item.name;
|
|
15184
15310
|
const children = item.children;
|
|
15311
|
+
const description = item.description;
|
|
15312
|
+
const icon = item.icon;
|
|
15185
15313
|
return {
|
|
15186
15314
|
id: item.id || uuidGenerator$2.uuidv4(),
|
|
15187
15315
|
name: typeof name === "function" ? name : () => name,
|
|
@@ -15199,8 +15327,8 @@ function createAction(item) {
|
|
|
15199
15327
|
: () => [],
|
|
15200
15328
|
isReadonlyAllowed: item.isReadonlyAllowed || false,
|
|
15201
15329
|
separator: item.separator || false,
|
|
15202
|
-
icon:
|
|
15203
|
-
description:
|
|
15330
|
+
icon: typeof icon === "function" ? icon : () => icon || "",
|
|
15331
|
+
description: typeof description === "function" ? description : () => description || "",
|
|
15204
15332
|
textColor: item.textColor,
|
|
15205
15333
|
sequence: item.sequence || 0,
|
|
15206
15334
|
};
|
|
@@ -16666,7 +16794,7 @@ function getChartTimeOptions(labels, labelFormat, locale) {
|
|
|
16666
16794
|
function convertDateFormatForMoment(format) {
|
|
16667
16795
|
format = format.replace(/y/g, "Y");
|
|
16668
16796
|
format = format.replace(/d/g, "D");
|
|
16669
|
-
// "m" before "h"
|
|
16797
|
+
// "m" before "h" === month, "m" after "h" === minute
|
|
16670
16798
|
const indexH = format.indexOf("h");
|
|
16671
16799
|
if (indexH >= 0) {
|
|
16672
16800
|
format = format.slice(0, indexH).replace(/m/g, "M") + format.slice(indexH);
|
|
@@ -17520,6 +17648,7 @@ function getChartMenu(figureId, onFigureDeleted, env) {
|
|
|
17520
17648
|
env.model.dispatch("SELECT_FIGURE", { id: figureId });
|
|
17521
17649
|
env.openSidePanel("ChartPanel");
|
|
17522
17650
|
},
|
|
17651
|
+
icon: "o-spreadsheet-Icon.EDIT",
|
|
17523
17652
|
},
|
|
17524
17653
|
getCopyMenuItem(figureId, env),
|
|
17525
17654
|
getCutMenuItem(figureId, env),
|
|
@@ -17551,6 +17680,7 @@ function getImageMenuRegistry(figureId, onFigureDeleted, env) {
|
|
|
17551
17680
|
width,
|
|
17552
17681
|
});
|
|
17553
17682
|
},
|
|
17683
|
+
icon: "o-spreadsheet-Icon.REFRESH",
|
|
17554
17684
|
},
|
|
17555
17685
|
getDeleteMenuItem(figureId, onFigureDeleted, env),
|
|
17556
17686
|
];
|
|
@@ -17567,6 +17697,7 @@ function getCopyMenuItem(figureId, env) {
|
|
|
17567
17697
|
env.model.dispatch("COPY");
|
|
17568
17698
|
await env.clipboard.write(env.model.getters.getClipboardContent());
|
|
17569
17699
|
},
|
|
17700
|
+
icon: "o-spreadsheet-Icon.COPY",
|
|
17570
17701
|
};
|
|
17571
17702
|
}
|
|
17572
17703
|
function getCutMenuItem(figureId, env) {
|
|
@@ -17580,6 +17711,7 @@ function getCutMenuItem(figureId, env) {
|
|
|
17580
17711
|
env.model.dispatch("CUT");
|
|
17581
17712
|
await env.clipboard.write(env.model.getters.getClipboardContent());
|
|
17582
17713
|
},
|
|
17714
|
+
icon: "o-spreadsheet-Icon.CUT",
|
|
17583
17715
|
};
|
|
17584
17716
|
}
|
|
17585
17717
|
function getDeleteMenuItem(figureId, onFigureDeleted, env) {
|
|
@@ -17594,6 +17726,7 @@ function getDeleteMenuItem(figureId, onFigureDeleted, env) {
|
|
|
17594
17726
|
});
|
|
17595
17727
|
onFigureDeleted();
|
|
17596
17728
|
},
|
|
17729
|
+
icon: "o-spreadsheet-Icon.DELETE",
|
|
17597
17730
|
};
|
|
17598
17731
|
}
|
|
17599
17732
|
|
|
@@ -18661,7 +18794,7 @@ const insertFunctionMin = {
|
|
|
18661
18794
|
};
|
|
18662
18795
|
const categorieFunctionAll = {
|
|
18663
18796
|
name: _lt("All"),
|
|
18664
|
-
children: allFunctionListMenuBuilder
|
|
18797
|
+
children: [allFunctionListMenuBuilder],
|
|
18665
18798
|
};
|
|
18666
18799
|
function allFunctionListMenuBuilder() {
|
|
18667
18800
|
const fnNames = functionRegistry.getKeys();
|
|
@@ -18993,7 +19126,10 @@ const formatNumberAutomatic = {
|
|
|
18993
19126
|
};
|
|
18994
19127
|
const formatNumberNumber = {
|
|
18995
19128
|
name: _lt("Number"),
|
|
18996
|
-
description:
|
|
19129
|
+
description: (env) => formatValue(1000.12, {
|
|
19130
|
+
format: "#,##0.00",
|
|
19131
|
+
locale: env.model.getters.getLocale(),
|
|
19132
|
+
}),
|
|
18997
19133
|
execute: (env) => setFormatter(env, "#,##0.00"),
|
|
18998
19134
|
isActive: (env) => isFormatSelected(env, "#,##0.00"),
|
|
18999
19135
|
};
|
|
@@ -19004,21 +19140,34 @@ const formatPercent = {
|
|
|
19004
19140
|
};
|
|
19005
19141
|
const formatNumberPercent = {
|
|
19006
19142
|
name: _lt("Percent"),
|
|
19007
|
-
description:
|
|
19143
|
+
description: (env) => formatValue(0.1012, {
|
|
19144
|
+
format: "0.00%",
|
|
19145
|
+
locale: env.model.getters.getLocale(),
|
|
19146
|
+
}),
|
|
19008
19147
|
execute: FORMAT_PERCENT_ACTION,
|
|
19009
19148
|
isActive: (env) => isFormatSelected(env, "0.00%"),
|
|
19010
19149
|
};
|
|
19011
19150
|
const formatNumberCurrency = {
|
|
19012
19151
|
name: _lt("Currency"),
|
|
19013
|
-
description:
|
|
19014
|
-
|
|
19015
|
-
|
|
19152
|
+
description: (env) => formatValue(1000.12, {
|
|
19153
|
+
format: env.model.config.defaultCurrencyFormat,
|
|
19154
|
+
locale: env.model.getters.getLocale(),
|
|
19155
|
+
}),
|
|
19156
|
+
execute: (env) => setFormatter(env, env.model.config.defaultCurrencyFormat),
|
|
19157
|
+
isActive: (env) => isFormatSelected(env, env.model.config.defaultCurrencyFormat),
|
|
19016
19158
|
};
|
|
19017
19159
|
const formatNumberCurrencyRounded = {
|
|
19018
19160
|
name: _lt("Currency rounded"),
|
|
19019
|
-
description:
|
|
19020
|
-
|
|
19021
|
-
|
|
19161
|
+
description: (env) => formatValue(1000, {
|
|
19162
|
+
format: roundFormat(env.model.config.defaultCurrencyFormat),
|
|
19163
|
+
locale: env.model.getters.getLocale(),
|
|
19164
|
+
}),
|
|
19165
|
+
execute: (env) => setFormatter(env, roundFormat(env.model.config.defaultCurrencyFormat)),
|
|
19166
|
+
isActive: (env) => isFormatSelected(env, roundFormat(env.model.config.defaultCurrencyFormat)),
|
|
19167
|
+
isVisible: (env) => {
|
|
19168
|
+
const currencyFormat = env.model.config.defaultCurrencyFormat;
|
|
19169
|
+
return currencyFormat !== roundFormat(currencyFormat);
|
|
19170
|
+
},
|
|
19022
19171
|
};
|
|
19023
19172
|
const formatCustomCurrency = {
|
|
19024
19173
|
name: _lt("Custom currency"),
|
|
@@ -19027,19 +19176,37 @@ const formatCustomCurrency = {
|
|
|
19027
19176
|
};
|
|
19028
19177
|
const formatNumberDate = {
|
|
19029
19178
|
name: _lt("Date"),
|
|
19030
|
-
description:
|
|
19179
|
+
description: (env) => {
|
|
19180
|
+
const locale = env.model.getters.getLocale();
|
|
19181
|
+
return formatValue(parseLiteral("9/26/2023", DEFAULT_LOCALE), {
|
|
19182
|
+
format: locale.dateFormat,
|
|
19183
|
+
locale,
|
|
19184
|
+
});
|
|
19185
|
+
},
|
|
19031
19186
|
execute: (env) => setFormatter(env, env.model.getters.getLocale().dateFormat),
|
|
19032
19187
|
isActive: (env) => isFormatSelected(env, env.model.getters.getLocale().dateFormat),
|
|
19033
19188
|
};
|
|
19034
19189
|
const formatNumberTime = {
|
|
19035
19190
|
name: _lt("Time"),
|
|
19036
|
-
description:
|
|
19191
|
+
description: (env) => {
|
|
19192
|
+
const locale = env.model.getters.getLocale();
|
|
19193
|
+
return formatValue(parseLiteral("9/26/2023 10:43:00 PM", DEFAULT_LOCALE), {
|
|
19194
|
+
format: locale.timeFormat,
|
|
19195
|
+
locale,
|
|
19196
|
+
});
|
|
19197
|
+
},
|
|
19037
19198
|
execute: (env) => setFormatter(env, env.model.getters.getLocale().timeFormat),
|
|
19038
19199
|
isActive: (env) => isFormatSelected(env, env.model.getters.getLocale().timeFormat),
|
|
19039
19200
|
};
|
|
19040
19201
|
const formatNumberDateTime = {
|
|
19041
19202
|
name: _lt("Date time"),
|
|
19042
|
-
description:
|
|
19203
|
+
description: (env) => {
|
|
19204
|
+
const locale = env.model.getters.getLocale();
|
|
19205
|
+
return formatValue(parseLiteral("9/26/2023 22:43:00", DEFAULT_LOCALE), {
|
|
19206
|
+
format: locale.dateFormat + " " + locale.timeFormat,
|
|
19207
|
+
locale,
|
|
19208
|
+
});
|
|
19209
|
+
},
|
|
19043
19210
|
execute: (env) => {
|
|
19044
19211
|
const locale = env.model.getters.getLocale();
|
|
19045
19212
|
setFormatter(env, locale.dateFormat + " " + locale.timeFormat);
|
|
@@ -19111,7 +19278,7 @@ const formatAlignment = {
|
|
|
19111
19278
|
};
|
|
19112
19279
|
const formatAlignmentHorizontal = {
|
|
19113
19280
|
name: _lt("Horizontal align"),
|
|
19114
|
-
icon:
|
|
19281
|
+
icon: (env) => getHorizontalAlignmentIcon(env),
|
|
19115
19282
|
};
|
|
19116
19283
|
const formatAlignmentLeft = {
|
|
19117
19284
|
name: _lt("Left"),
|
|
@@ -19136,46 +19303,50 @@ const formatAlignmentRight = {
|
|
|
19136
19303
|
};
|
|
19137
19304
|
const formatAlignmentVertical = {
|
|
19138
19305
|
name: _lt("Vertical align"),
|
|
19139
|
-
icon:
|
|
19306
|
+
icon: (env) => getVerticalAlignmentIcon(env),
|
|
19140
19307
|
};
|
|
19141
19308
|
const formatAlignmentTop = {
|
|
19142
19309
|
name: _lt("Top"),
|
|
19143
19310
|
execute: (env) => setStyle(env, { verticalAlign: "top" }),
|
|
19144
|
-
isActive: (env) => (env
|
|
19311
|
+
isActive: (env) => getVerticalAlign(env) === "top",
|
|
19145
19312
|
icon: "o-spreadsheet-Icon.ALIGN_TOP",
|
|
19146
19313
|
};
|
|
19147
19314
|
const formatAlignmentMiddle = {
|
|
19148
19315
|
name: _lt("Middle"),
|
|
19149
19316
|
execute: (env) => setStyle(env, { verticalAlign: "middle" }),
|
|
19150
|
-
isActive: (env) => (env
|
|
19317
|
+
isActive: (env) => getVerticalAlign(env) === "middle",
|
|
19151
19318
|
icon: "o-spreadsheet-Icon.ALIGN_MIDDLE",
|
|
19152
19319
|
};
|
|
19153
19320
|
const formatAlignmentBottom = {
|
|
19154
19321
|
name: _lt("Bottom"),
|
|
19155
19322
|
execute: (env) => setStyle(env, { verticalAlign: "bottom" }),
|
|
19156
|
-
isActive: (env) => (env
|
|
19323
|
+
isActive: (env) => getVerticalAlign(env) === "bottom",
|
|
19157
19324
|
icon: "o-spreadsheet-Icon.ALIGN_BOTTOM",
|
|
19158
19325
|
};
|
|
19159
|
-
const
|
|
19326
|
+
const formatWrappingIcon = {
|
|
19160
19327
|
name: _lt("Wrapping"),
|
|
19161
19328
|
icon: "o-spreadsheet-Icon.WRAPPING_OVERFLOW",
|
|
19162
19329
|
};
|
|
19330
|
+
const formatWrapping = {
|
|
19331
|
+
name: _lt("Wrapping"),
|
|
19332
|
+
icon: (env) => getWrapModeIcon(env),
|
|
19333
|
+
};
|
|
19163
19334
|
const formatWrappingOverflow = {
|
|
19164
19335
|
name: _lt("Overflow"),
|
|
19165
19336
|
execute: (env) => setStyle(env, { wrapping: "overflow" }),
|
|
19166
|
-
isActive: (env) => (env
|
|
19337
|
+
isActive: (env) => getWrappingMode(env) === "overflow",
|
|
19167
19338
|
icon: "o-spreadsheet-Icon.WRAPPING_OVERFLOW",
|
|
19168
19339
|
};
|
|
19169
19340
|
const formatWrappingWrap = {
|
|
19170
19341
|
name: _lt("Wrap"),
|
|
19171
19342
|
execute: (env) => setStyle(env, { wrapping: "wrap" }),
|
|
19172
|
-
isActive: (env) => env
|
|
19343
|
+
isActive: (env) => getWrappingMode(env) === "wrap",
|
|
19173
19344
|
icon: "o-spreadsheet-Icon.WRAPPING_WRAP",
|
|
19174
19345
|
};
|
|
19175
19346
|
const formatWrappingClip = {
|
|
19176
19347
|
name: _lt("Clip"),
|
|
19177
19348
|
execute: (env) => setStyle(env, { wrapping: "clip" }),
|
|
19178
|
-
isActive: (env) => env
|
|
19349
|
+
isActive: (env) => getWrappingMode(env) === "clip",
|
|
19179
19350
|
icon: "o-spreadsheet-Icon.WRAPPING_CLIP",
|
|
19180
19351
|
};
|
|
19181
19352
|
const textColor = {
|
|
@@ -19191,14 +19362,6 @@ const formatCF = {
|
|
|
19191
19362
|
execute: OPEN_CF_SIDEPANEL_ACTION,
|
|
19192
19363
|
icon: "o-spreadsheet-Icon.CONDITIONAL_FORMAT",
|
|
19193
19364
|
};
|
|
19194
|
-
const paintFormat = {
|
|
19195
|
-
name: _lt("Paint Format"),
|
|
19196
|
-
execute: (env) => env.model.dispatch("ACTIVATE_PAINT_FORMAT", {
|
|
19197
|
-
target: env.model.getters.getSelectedZones(),
|
|
19198
|
-
}),
|
|
19199
|
-
icon: "o-spreadsheet-Icon.PAINT_FORMAT",
|
|
19200
|
-
isActive: (env) => env.model.getters.isPaintingFormat(),
|
|
19201
|
-
};
|
|
19202
19365
|
const clearFormat = {
|
|
19203
19366
|
name: _lt("Clear formatting"),
|
|
19204
19367
|
description: "Ctrl+<",
|
|
@@ -19238,6 +19401,53 @@ function getHorizontalAlign(env) {
|
|
|
19238
19401
|
}
|
|
19239
19402
|
const cell = env.model.getters.getActiveCell();
|
|
19240
19403
|
return cell.defaultAlign;
|
|
19404
|
+
}
|
|
19405
|
+
function getVerticalAlign(env) {
|
|
19406
|
+
const style = env.model.getters.getCurrentStyle();
|
|
19407
|
+
if (style.verticalAlign) {
|
|
19408
|
+
return style.verticalAlign;
|
|
19409
|
+
}
|
|
19410
|
+
return DEFAULT_VERTICAL_ALIGN;
|
|
19411
|
+
}
|
|
19412
|
+
function getWrappingMode(env) {
|
|
19413
|
+
const style = env.model.getters.getCurrentStyle();
|
|
19414
|
+
if (style.wrapping) {
|
|
19415
|
+
return style.wrapping;
|
|
19416
|
+
}
|
|
19417
|
+
return DEFAULT_WRAPPING_MODE;
|
|
19418
|
+
}
|
|
19419
|
+
function getHorizontalAlignmentIcon(env) {
|
|
19420
|
+
const horizontalAlign = getHorizontalAlign(env);
|
|
19421
|
+
switch (horizontalAlign) {
|
|
19422
|
+
case "right":
|
|
19423
|
+
return "o-spreadsheet-Icon.ALIGN_RIGHT";
|
|
19424
|
+
case "center":
|
|
19425
|
+
return "o-spreadsheet-Icon.ALIGN_CENTER";
|
|
19426
|
+
default:
|
|
19427
|
+
return "o-spreadsheet-Icon.ALIGN_LEFT";
|
|
19428
|
+
}
|
|
19429
|
+
}
|
|
19430
|
+
function getVerticalAlignmentIcon(env) {
|
|
19431
|
+
const verticalAlign = getVerticalAlign(env);
|
|
19432
|
+
switch (verticalAlign) {
|
|
19433
|
+
case "top":
|
|
19434
|
+
return "o-spreadsheet-Icon.ALIGN_TOP";
|
|
19435
|
+
case "middle":
|
|
19436
|
+
return "o-spreadsheet-Icon.ALIGN_MIDDLE";
|
|
19437
|
+
default:
|
|
19438
|
+
return "o-spreadsheet-Icon.ALIGN_BOTTOM";
|
|
19439
|
+
}
|
|
19440
|
+
}
|
|
19441
|
+
function getWrapModeIcon(env) {
|
|
19442
|
+
const wrapMode = getWrappingMode(env);
|
|
19443
|
+
switch (wrapMode) {
|
|
19444
|
+
case "wrap":
|
|
19445
|
+
return "o-spreadsheet-Icon.WRAPPING_WRAP";
|
|
19446
|
+
case "clip":
|
|
19447
|
+
return "o-spreadsheet-Icon.WRAPPING_CLIP";
|
|
19448
|
+
default:
|
|
19449
|
+
return "o-spreadsheet-Icon.WRAPPING_OVERFLOW";
|
|
19450
|
+
}
|
|
19241
19451
|
}
|
|
19242
19452
|
|
|
19243
19453
|
var ACTION_FORMAT = /*#__PURE__*/Object.freeze({
|
|
@@ -19269,6 +19479,7 @@ var ACTION_FORMAT = /*#__PURE__*/Object.freeze({
|
|
|
19269
19479
|
formatAlignmentTop: formatAlignmentTop,
|
|
19270
19480
|
formatAlignmentMiddle: formatAlignmentMiddle,
|
|
19271
19481
|
formatAlignmentBottom: formatAlignmentBottom,
|
|
19482
|
+
formatWrappingIcon: formatWrappingIcon,
|
|
19272
19483
|
formatWrapping: formatWrapping,
|
|
19273
19484
|
formatWrappingOverflow: formatWrappingOverflow,
|
|
19274
19485
|
formatWrappingWrap: formatWrappingWrap,
|
|
@@ -19276,7 +19487,6 @@ var ACTION_FORMAT = /*#__PURE__*/Object.freeze({
|
|
|
19276
19487
|
textColor: textColor,
|
|
19277
19488
|
fillColor: fillColor,
|
|
19278
19489
|
formatCF: formatCF,
|
|
19279
|
-
paintFormat: paintFormat,
|
|
19280
19490
|
clearFormat: clearFormat
|
|
19281
19491
|
});
|
|
19282
19492
|
|
|
@@ -20039,7 +20249,7 @@ topbarMenuRegistry
|
|
|
20039
20249
|
separator: true,
|
|
20040
20250
|
})
|
|
20041
20251
|
.addChild("format_wrapping", ["format"], {
|
|
20042
|
-
...
|
|
20252
|
+
...formatWrappingIcon,
|
|
20043
20253
|
sequence: 80,
|
|
20044
20254
|
separator: true,
|
|
20045
20255
|
})
|
|
@@ -22329,17 +22539,45 @@ class CustomCurrencyPanel extends Component {
|
|
|
22329
22539
|
}
|
|
22330
22540
|
get formatProposals() {
|
|
22331
22541
|
const currency = this.availableCurrencies[this.state.selectedCurrencyIndex];
|
|
22332
|
-
const
|
|
22333
|
-
const
|
|
22334
|
-
const secondPosition = currency.position === "before" ? "after" : "before";
|
|
22542
|
+
const position = currency.position;
|
|
22543
|
+
const opposite = currency.position === "before" ? "after" : "before";
|
|
22335
22544
|
const symbol = this.state.currencySymbol.trim() ? this.state.currencySymbol : "";
|
|
22336
22545
|
const code = this.state.currencyCode.trim() ? this.state.currencyCode : "";
|
|
22337
|
-
|
|
22338
|
-
|
|
22339
|
-
|
|
22340
|
-
|
|
22341
|
-
|
|
22342
|
-
|
|
22546
|
+
const decimalPlaces = currency.decimalPlaces;
|
|
22547
|
+
if (!symbol && !code) {
|
|
22548
|
+
return [];
|
|
22549
|
+
}
|
|
22550
|
+
const simple = symbol ? createCurrencyFormat({ symbol, position, decimalPlaces }) : "";
|
|
22551
|
+
const rounded = simple ? roundFormat(simple) : "";
|
|
22552
|
+
const simpleWithCode = createCurrencyFormat({ symbol, position, decimalPlaces, code });
|
|
22553
|
+
const roundedWithCode = roundFormat(simpleWithCode);
|
|
22554
|
+
const simpleOpposite = symbol
|
|
22555
|
+
? createCurrencyFormat({ symbol, position: opposite, decimalPlaces })
|
|
22556
|
+
: "";
|
|
22557
|
+
const roundedOpposite = simpleOpposite ? roundFormat(simpleOpposite) : "";
|
|
22558
|
+
const simpleOppositeWithCode = createCurrencyFormat({
|
|
22559
|
+
symbol,
|
|
22560
|
+
position: opposite,
|
|
22561
|
+
decimalPlaces,
|
|
22562
|
+
code,
|
|
22563
|
+
});
|
|
22564
|
+
const roundedOppositeWithCode = roundFormat(simpleOppositeWithCode);
|
|
22565
|
+
const formats = new Set([
|
|
22566
|
+
rounded,
|
|
22567
|
+
simple,
|
|
22568
|
+
roundedWithCode,
|
|
22569
|
+
simpleWithCode,
|
|
22570
|
+
roundedOpposite,
|
|
22571
|
+
simpleOpposite,
|
|
22572
|
+
roundedOppositeWithCode,
|
|
22573
|
+
simpleOppositeWithCode,
|
|
22574
|
+
]);
|
|
22575
|
+
return [...formats]
|
|
22576
|
+
.filter((format) => format !== "")
|
|
22577
|
+
.map((format) => ({
|
|
22578
|
+
format,
|
|
22579
|
+
example: formatValue(1000.0, { format, locale: this.env.model.getters.getLocale() }),
|
|
22580
|
+
}));
|
|
22343
22581
|
}
|
|
22344
22582
|
get isSameFormat() {
|
|
22345
22583
|
const selectedFormat = this.formatProposals[this.state.selectedFormatIndex];
|
|
@@ -22396,41 +22634,6 @@ class CustomCurrencyPanel extends Component {
|
|
|
22396
22634
|
initAvailableCurrencies() {
|
|
22397
22635
|
this.state.selectedCurrencyIndex = 0;
|
|
22398
22636
|
}
|
|
22399
|
-
initProposalBases(decimalPlaces) {
|
|
22400
|
-
const result = [{ format: "#,##0", example: "1,000" }];
|
|
22401
|
-
const decimalRepresentation = decimalPlaces ? "." + "0".repeat(decimalPlaces) : "";
|
|
22402
|
-
if (decimalRepresentation) {
|
|
22403
|
-
result.push({
|
|
22404
|
-
format: "#,##0" + decimalRepresentation,
|
|
22405
|
-
example: "1,000" + decimalRepresentation,
|
|
22406
|
-
});
|
|
22407
|
-
}
|
|
22408
|
-
return result;
|
|
22409
|
-
}
|
|
22410
|
-
createFormatProposals(proposalBases, symbol, code, position) {
|
|
22411
|
-
let formatProposals = [];
|
|
22412
|
-
// 1 - add proposal with symbol and without code
|
|
22413
|
-
if (symbol) {
|
|
22414
|
-
for (let base of proposalBases) {
|
|
22415
|
-
formatProposals.push(this.createFormatProposal(position, base.example, base.format, symbol));
|
|
22416
|
-
}
|
|
22417
|
-
}
|
|
22418
|
-
// 2 - if code exist --> add more proposal with symbol and with code
|
|
22419
|
-
if (code) {
|
|
22420
|
-
for (let base of proposalBases) {
|
|
22421
|
-
const expression = (position === "after" ? " " : "") + code + " " + symbol;
|
|
22422
|
-
formatProposals.push(this.createFormatProposal(position, base.example, base.format, expression));
|
|
22423
|
-
}
|
|
22424
|
-
}
|
|
22425
|
-
return formatProposals;
|
|
22426
|
-
}
|
|
22427
|
-
createFormatProposal(position, baseExample, formatBase, expression) {
|
|
22428
|
-
const formatExpression = "[$" + expression + "]";
|
|
22429
|
-
return {
|
|
22430
|
-
example: position === "before" ? expression + baseExample : baseExample + expression,
|
|
22431
|
-
format: position === "before" ? formatExpression + formatBase : formatBase + formatExpression,
|
|
22432
|
-
};
|
|
22433
|
-
}
|
|
22434
22637
|
getCommonFormat() {
|
|
22435
22638
|
const selectedZones = this.env.model.getters.getSelectedZones();
|
|
22436
22639
|
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
@@ -23233,7 +23436,7 @@ class ContentEditableHelper {
|
|
|
23233
23436
|
selection.removeAllRanges();
|
|
23234
23437
|
selection.addRange(range);
|
|
23235
23438
|
}
|
|
23236
|
-
if (start
|
|
23439
|
+
if (start === end && start === 0) {
|
|
23237
23440
|
range.setStart(this.el, 0);
|
|
23238
23441
|
range.setEnd(this.el, 0);
|
|
23239
23442
|
}
|
|
@@ -23486,7 +23689,7 @@ class ContentEditableHelper {
|
|
|
23486
23689
|
}, 0);
|
|
23487
23690
|
}
|
|
23488
23691
|
}
|
|
23489
|
-
if (nodeToFind.nodeName === "P" && !isFirstParagraph && nodeToFind.textContent
|
|
23692
|
+
if (nodeToFind.nodeName === "P" && !isFirstParagraph && nodeToFind.textContent === "") {
|
|
23490
23693
|
usedCharacters++;
|
|
23491
23694
|
}
|
|
23492
23695
|
return usedCharacters;
|
|
@@ -25033,6 +25236,14 @@ function useInterval(callback, delay) {
|
|
|
25033
25236
|
};
|
|
25034
25237
|
}
|
|
25035
25238
|
|
|
25239
|
+
const CURSOR_SVG = /*xml*/ `
|
|
25240
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14" height="16"><path d="M6.5.4c1.3-.8 2.9-.1 3.8 1.4l2.9 5.1c.2.4.9 1.6-.4 2.3l-1.6.9 1.8 3.1c.2.4.1 1-.2 1.2l-1.6 1c-.3.1-.9 0-1.1-.4l-1.8-3.1-1.6 1c-.6.4-1.7 0-2.2-.8L0 4.3"/><path fill="#fff" d="M9.1 2a1.4 1.1 60 0 0-1.7-.6L5.5 2.5l.9 1.6-1 .6-.9-1.6-.6.4 1.8 3.1-1.3.7-1.8-3.1-1 .6 3.8 6.6 6.8-3.98M3.9 8.8 10.82 5l.795 1.4-6.81 3.96"/></svg>
|
|
25241
|
+
`;
|
|
25242
|
+
css /* scss */ `
|
|
25243
|
+
.o-paint-format-cursor {
|
|
25244
|
+
cursor: url("data:image/svg+xml,${encodeURIComponent(CURSOR_SVG)}"), auto;
|
|
25245
|
+
}
|
|
25246
|
+
`;
|
|
25036
25247
|
function useCellHovered(env, gridRef, callback) {
|
|
25037
25248
|
let hoveredPosition = {
|
|
25038
25249
|
col: undefined,
|
|
@@ -25156,6 +25367,12 @@ class GridOverlay extends Component {
|
|
|
25156
25367
|
}
|
|
25157
25368
|
return this.gridOverlay.el;
|
|
25158
25369
|
}
|
|
25370
|
+
get style() {
|
|
25371
|
+
return this.props.gridOverlayDimensions;
|
|
25372
|
+
}
|
|
25373
|
+
get isPaintingFormat() {
|
|
25374
|
+
return this.env.model.getters.isPaintingFormat();
|
|
25375
|
+
}
|
|
25159
25376
|
onMouseDown(ev) {
|
|
25160
25377
|
if (ev.button > 0) {
|
|
25161
25378
|
// not main button, probably a context menu
|
|
@@ -26333,6 +26550,9 @@ class Grid extends Component {
|
|
|
26333
26550
|
else if (this.menuState.isOpen) {
|
|
26334
26551
|
this.closeMenu();
|
|
26335
26552
|
}
|
|
26553
|
+
else if (this.env.model.getters.isPaintingFormat()) {
|
|
26554
|
+
this.env.model.dispatch("CANCEL_PAINT_FORMAT");
|
|
26555
|
+
}
|
|
26336
26556
|
else {
|
|
26337
26557
|
this.env.model.dispatch("CLEAN_CLIPBOARD_HIGHLIGHT");
|
|
26338
26558
|
}
|
|
@@ -27535,8 +27755,8 @@ function convertXlsxFormat(numFmtId, formats, warningManager) {
|
|
|
27535
27755
|
throw new Error("Multiple escaped blocks in format");
|
|
27536
27756
|
}
|
|
27537
27757
|
convertedFormat = convertedFormat.replace(/"(.*)"/g, "[$$$1]"); // replace '"..."' by '[$...]'
|
|
27538
|
-
convertedFormat = convertedFormat.replace(/_.{1}/g, ""); // _
|
|
27539
|
-
convertedFormat = convertedFormat.replace(/\*.{1}/g, ""); // *
|
|
27758
|
+
convertedFormat = convertedFormat.replace(/_.{1}/g, ""); // _ === ignore width of next char for align purposes. Not supported ATM
|
|
27759
|
+
convertedFormat = convertedFormat.replace(/\*.{1}/g, ""); // * === repeat next character enough to fill the line. Not supported ATM
|
|
27540
27760
|
convertedFormat = convertedFormat.replace(/\\ /g, " "); // unescape spaces
|
|
27541
27761
|
convertedFormat = convertedFormat.replace(/\\./g, (match) => match[1]); // unescape other characters
|
|
27542
27762
|
if (isXlsxDateFormat(convertedFormat)) {
|
|
@@ -28828,29 +29048,26 @@ function escapeXml(strings, ...expressions) {
|
|
|
28828
29048
|
return new XMLString(concat(str));
|
|
28829
29049
|
}
|
|
28830
29050
|
/**
|
|
28831
|
-
* Removes the namespace of all the xml tags in the string.
|
|
29051
|
+
* Removes the escaped namespace of all the xml tags in the string.
|
|
28832
29052
|
*
|
|
28833
|
-
* Eg. : "
|
|
29053
|
+
* Eg. : "NAMESPACEnsNAMESPACEtest a" => "test a"
|
|
28834
29054
|
*/
|
|
28835
|
-
function
|
|
28836
|
-
return
|
|
29055
|
+
function removeTagEscapedNamespaces(tag) {
|
|
29056
|
+
return tag.replace(/NAMESPACE.*NAMESPACE(.*)/, "$1");
|
|
28837
29057
|
}
|
|
28838
29058
|
/**
|
|
28839
|
-
*
|
|
29059
|
+
* Encase the namespaces in the element's tags with NAMESPACE string
|
|
28840
29060
|
*
|
|
28841
|
-
*
|
|
28842
|
-
*/
|
|
28843
|
-
function escapeNamespaces(query) {
|
|
28844
|
-
return query.replace(/([a-z0-9]+):(?=[a-z0-9]+)/gi, "$1\\:");
|
|
28845
|
-
}
|
|
28846
|
-
/**
|
|
28847
|
-
* Return true if the querySelector ignores the namespaces when searching for a tag in the DOM.
|
|
29061
|
+
* e.g. <x:foo> becomes <NAMESPACExNAMESPACEFoo>
|
|
28848
29062
|
*
|
|
28849
|
-
*
|
|
29063
|
+
* That's useful because namespaces aren't supported by the HTML specification, so it's arbitrary whether a HTML parser/querySelector
|
|
29064
|
+
* implementation will support namespaces in the tags or not.
|
|
28850
29065
|
*/
|
|
28851
|
-
function
|
|
28852
|
-
|
|
28853
|
-
|
|
29066
|
+
function escapeTagNamespaces(str) {
|
|
29067
|
+
return str.replaceAll(/(<\/?)([a-zA-Z0-9]+):([a-zA-Z0-9]+)/g, "$1" + "NAMESPACE" + "$2" + "NAMESPACE" + "$3");
|
|
29068
|
+
}
|
|
29069
|
+
function escapeQueryNameSpaces(query) {
|
|
29070
|
+
return query.replaceAll(/([a-zA-Z0-9]+):([a-zA-Z0-9]+)/g, "NAMESPACE" + "$1" + "NAMESPACE" + "$2");
|
|
28854
29071
|
}
|
|
28855
29072
|
|
|
28856
29073
|
class AttributeValue {
|
|
@@ -28880,14 +29097,20 @@ class XlsxBaseExtractor {
|
|
|
28880
29097
|
// The xml file we are currently parsing. We should have one Extractor class by XLSXImportFile, but
|
|
28881
29098
|
// the XLSXImportFile contains both the main .xml file, and the .rels file
|
|
28882
29099
|
currentFile = undefined;
|
|
28883
|
-
|
|
28884
|
-
|
|
29100
|
+
/**
|
|
29101
|
+
* /!\ Important : There should be no namespaces in the tags of the XML files.
|
|
29102
|
+
*
|
|
29103
|
+
* This class use native querySelector and querySelectorAll, that's used for HTML (not XML). These aren't supposed to
|
|
29104
|
+
* handled namespaces, as they are not supported by the HTML specification. Some implementations (most browsers) do
|
|
29105
|
+
* actually support namespaces, but some don't (e.g. jsdom).
|
|
29106
|
+
*
|
|
29107
|
+
* The namespace should be escaped as with NAMESPACE string (eg. <t:foo> => <NAMESPACEtNAMESPACEfoo>).
|
|
29108
|
+
*/
|
|
28885
29109
|
constructor(rootFile, xlsxStructure, warningManager) {
|
|
28886
29110
|
this.rootFile = rootFile;
|
|
28887
29111
|
this.currentFile = rootFile.file.fileName;
|
|
28888
29112
|
this.xlsxFileStructure = xlsxStructure;
|
|
28889
29113
|
this.warningManager = warningManager;
|
|
28890
|
-
this.areNamespaceIgnored = areNamespaceIgnoredByQuerySelector();
|
|
28891
29114
|
this.relationships = {};
|
|
28892
29115
|
if (rootFile.rels) {
|
|
28893
29116
|
this.extractRelationships(rootFile.rels).map((rel) => {
|
|
@@ -29113,29 +29336,13 @@ class XlsxBaseExtractor {
|
|
|
29113
29336
|
throw new Error("Cannot find target file");
|
|
29114
29337
|
return f;
|
|
29115
29338
|
}
|
|
29116
|
-
/**
|
|
29117
|
-
* Wrapper of querySelector, but we'll remove the namespaces from the query if areNamespacesIgnored is true.
|
|
29118
|
-
*
|
|
29119
|
-
* Why we need to do this :
|
|
29120
|
-
* - For an XML "<t:test />"
|
|
29121
|
-
* - on Jest(jsdom) : xml.querySelector("test") == null, xml.querySelector("t\\:test") == <t:test />
|
|
29122
|
-
* - on Browser : xml.querySelector("test") == <t:test />, xml.querySelector("t\\:test") == null
|
|
29123
|
-
*/
|
|
29124
29339
|
querySelector(element, query) {
|
|
29125
|
-
|
|
29126
|
-
return element.querySelector(
|
|
29340
|
+
const escapedQuery = escapeQueryNameSpaces(query);
|
|
29341
|
+
return element.querySelector(escapedQuery);
|
|
29127
29342
|
}
|
|
29128
|
-
/**
|
|
29129
|
-
* Wrapper of querySelectorAll, but we'll remove the namespaces from the query if areNamespacesIgnored is true.
|
|
29130
|
-
*
|
|
29131
|
-
* Why we need to do this :
|
|
29132
|
-
* - For an XML "<t:test />"
|
|
29133
|
-
* - on Jest(jsdom) : xml.querySelectorAll("test") == [], xml.querySelectorAll("t\\:test") == [<t:test />]
|
|
29134
|
-
* - on Browser : xml.querySelectorAll("test") == [<t:test />], xml.querySelectorAll("t\\:test") == []
|
|
29135
|
-
*/
|
|
29136
29343
|
querySelectorAll(element, query) {
|
|
29137
|
-
|
|
29138
|
-
return element.querySelectorAll(
|
|
29344
|
+
const escapedQuery = escapeQueryNameSpaces(query);
|
|
29345
|
+
return element.querySelectorAll(escapedQuery);
|
|
29139
29346
|
}
|
|
29140
29347
|
/**
|
|
29141
29348
|
* Get a color from its id in the Theme's colorScheme.
|
|
@@ -29375,7 +29582,7 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
|
|
|
29375
29582
|
throw new Error("Missing plot area in the chart definition.");
|
|
29376
29583
|
}
|
|
29377
29584
|
for (let child of plotAreaElement.children) {
|
|
29378
|
-
const tag =
|
|
29585
|
+
const tag = removeTagEscapedNamespaces(child.tagName);
|
|
29379
29586
|
if (XLSX_CHART_TYPES.some((chartType) => chartType === tag)) {
|
|
29380
29587
|
return tag;
|
|
29381
29588
|
}
|
|
@@ -29387,7 +29594,7 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
|
|
|
29387
29594
|
class XlsxFigureExtractor extends XlsxBaseExtractor {
|
|
29388
29595
|
extractFigures() {
|
|
29389
29596
|
return this.mapOnElements({ parent: this.rootFile.file.xml, query: "xdr:wsDr", children: true }, (figureElement) => {
|
|
29390
|
-
const anchorType =
|
|
29597
|
+
const anchorType = removeTagEscapedNamespaces(figureElement.tagName);
|
|
29391
29598
|
if (anchorType !== "twoCellAnchor") {
|
|
29392
29599
|
throw new Error("Only twoCellAnchor are supported for xlsx drawings.");
|
|
29393
29600
|
}
|
|
@@ -30021,7 +30228,8 @@ class XlsxReader {
|
|
|
30021
30228
|
for (let key of Object.keys(files)) {
|
|
30022
30229
|
// Random files can be in xlsx (like a bin file for printer settings)
|
|
30023
30230
|
if (key.endsWith(".xml") || key.endsWith(".rels")) {
|
|
30024
|
-
|
|
30231
|
+
const contentString = escapeTagNamespaces(files[key]);
|
|
30232
|
+
this.xmls[key] = parseXML(new XMLString(contentString));
|
|
30025
30233
|
}
|
|
30026
30234
|
else if (key.includes("media/image")) {
|
|
30027
30235
|
this.images.push({
|
|
@@ -31088,7 +31296,7 @@ class BordersPlugin extends CorePlugin {
|
|
|
31088
31296
|
}
|
|
31089
31297
|
/**
|
|
31090
31298
|
* Set the borders of a cell.
|
|
31091
|
-
* It overrides the current border if override
|
|
31299
|
+
* It overrides the current border if override === true.
|
|
31092
31300
|
*/
|
|
31093
31301
|
setBorder(sheetId, col, row, border, override = true) {
|
|
31094
31302
|
if (override || !this.borders?.[sheetId]?.[col]?.[row]?.vertical) {
|
|
@@ -32358,7 +32566,9 @@ class FigurePlugin extends CorePlugin {
|
|
|
32358
32566
|
const numHeader = this.getters.getNumberRows(sheetId);
|
|
32359
32567
|
let gridHeight = 0;
|
|
32360
32568
|
for (let i = 0; i < numHeader; i++) {
|
|
32361
|
-
|
|
32569
|
+
// TODO : since the row size is an UI value now, this doesn't work anymore. Using the default cell height is
|
|
32570
|
+
// a temporary solution at best, but is broken.
|
|
32571
|
+
gridHeight += this.getters.getUserRowSize(sheetId, i) || DEFAULT_CELL_HEIGHT;
|
|
32362
32572
|
}
|
|
32363
32573
|
const figures = this.getters.getFigures(sheetId);
|
|
32364
32574
|
for (const figure of figures) {
|
|
@@ -32784,33 +32994,15 @@ class FiltersPlugin extends CorePlugin {
|
|
|
32784
32994
|
}
|
|
32785
32995
|
|
|
32786
32996
|
class HeaderSizePlugin extends CorePlugin {
|
|
32787
|
-
static getters = ["
|
|
32997
|
+
static getters = ["getUserRowSize", "getColSize"];
|
|
32788
32998
|
sizes = {};
|
|
32789
32999
|
handle(cmd) {
|
|
32790
33000
|
switch (cmd.type) {
|
|
32791
33001
|
case "CREATE_SHEET": {
|
|
32792
|
-
|
|
32793
|
-
const sizes = {
|
|
32794
|
-
COL: computedSizes.COL.map((size) => ({
|
|
32795
|
-
manualSize: undefined,
|
|
32796
|
-
computedSize: lazy(size),
|
|
32797
|
-
})),
|
|
32798
|
-
ROW: computedSizes.ROW.map((size) => ({
|
|
32799
|
-
manualSize: undefined,
|
|
32800
|
-
computedSize: lazy(size),
|
|
32801
|
-
})),
|
|
32802
|
-
};
|
|
32803
|
-
this.history.update("sizes", cmd.sheetId, sizes);
|
|
33002
|
+
this.history.update("sizes", cmd.sheetId, { COL: [], ROW: [] });
|
|
32804
33003
|
break;
|
|
32805
33004
|
}
|
|
32806
33005
|
case "DUPLICATE_SHEET":
|
|
32807
|
-
// make sure the values are computed in case the original sheet is deleted
|
|
32808
|
-
for (const row of this.sizes[cmd.sheetId].ROW) {
|
|
32809
|
-
row.computedSize();
|
|
32810
|
-
}
|
|
32811
|
-
for (const col of this.sizes[cmd.sheetId].COL) {
|
|
32812
|
-
col.computedSize();
|
|
32813
|
-
}
|
|
32814
33006
|
this.history.update("sizes", cmd.sheetIdTo, deepCopy(this.sizes[cmd.sheetId]));
|
|
32815
33007
|
break;
|
|
32816
33008
|
case "DELETE_SHEET":
|
|
@@ -32819,21 +33011,8 @@ class HeaderSizePlugin extends CorePlugin {
|
|
|
32819
33011
|
this.history.update("sizes", sizes);
|
|
32820
33012
|
break;
|
|
32821
33013
|
case "REMOVE_COLUMNS_ROWS": {
|
|
32822
|
-
|
|
32823
|
-
|
|
32824
|
-
sizes.splice(headerIndex, 1);
|
|
32825
|
-
}
|
|
32826
|
-
const min = Math.min(...cmd.elements);
|
|
32827
|
-
sizes = sizes.map((size, row) => {
|
|
32828
|
-
if (cmd.dimension === "ROW" && row >= min) {
|
|
32829
|
-
// invalidate sizes
|
|
32830
|
-
return {
|
|
32831
|
-
manualSize: size.manualSize,
|
|
32832
|
-
computedSize: lazy(() => this.getRowTallestCellSize(cmd.sheetId, row)),
|
|
32833
|
-
};
|
|
32834
|
-
}
|
|
32835
|
-
return size;
|
|
32836
|
-
});
|
|
33014
|
+
const arr = this.sizes[cmd.sheetId][cmd.dimension];
|
|
33015
|
+
const sizes = removeIndexesFromArray(arr, cmd.elements);
|
|
32837
33016
|
this.history.update("sizes", cmd.sheetId, cmd.dimension, sizes);
|
|
32838
33017
|
break;
|
|
32839
33018
|
}
|
|
@@ -32842,51 +33021,18 @@ class HeaderSizePlugin extends CorePlugin {
|
|
|
32842
33021
|
const addIndex = getAddHeaderStartIndex(cmd.position, cmd.base);
|
|
32843
33022
|
const baseSize = sizes[cmd.base];
|
|
32844
33023
|
sizes.splice(addIndex, 0, ...Array(cmd.quantity).fill(baseSize));
|
|
32845
|
-
sizes = sizes.map((size, row) => {
|
|
32846
|
-
if (cmd.dimension === "ROW" && row > cmd.base + cmd.quantity) {
|
|
32847
|
-
// invalidate sizes
|
|
32848
|
-
return {
|
|
32849
|
-
manualSize: size.manualSize,
|
|
32850
|
-
computedSize: lazy(() => this.getRowTallestCellSize(cmd.sheetId, row)),
|
|
32851
|
-
};
|
|
32852
|
-
}
|
|
32853
|
-
return size;
|
|
32854
|
-
});
|
|
32855
33024
|
this.history.update("sizes", cmd.sheetId, cmd.dimension, sizes);
|
|
32856
33025
|
break;
|
|
32857
33026
|
}
|
|
32858
33027
|
case "RESIZE_COLUMNS_ROWS":
|
|
32859
|
-
|
|
32860
|
-
|
|
32861
|
-
|
|
32862
|
-
const size = height;
|
|
32863
|
-
this.history.update("sizes", cmd.sheetId, cmd.dimension, el, {
|
|
32864
|
-
manualSize: cmd.size || undefined,
|
|
32865
|
-
computedSize: lazy(size),
|
|
32866
|
-
});
|
|
32867
|
-
}
|
|
32868
|
-
else {
|
|
32869
|
-
this.history.update("sizes", cmd.sheetId, cmd.dimension, el, {
|
|
32870
|
-
manualSize: cmd.size || undefined,
|
|
32871
|
-
computedSize: lazy(cmd.size || DEFAULT_CELL_WIDTH),
|
|
32872
|
-
});
|
|
33028
|
+
if (cmd.dimension === "ROW") {
|
|
33029
|
+
for (const el of cmd.elements) {
|
|
33030
|
+
this.history.update("sizes", cmd.sheetId, cmd.dimension, el, cmd.size || undefined);
|
|
32873
33031
|
}
|
|
32874
33032
|
}
|
|
32875
|
-
|
|
32876
|
-
|
|
32877
|
-
|
|
32878
|
-
const { sheetId, row } = cmd;
|
|
32879
|
-
this.history.update("sizes", sheetId, "ROW", row, "computedSize", lazy(() => this.getRowTallestCellSize(sheetId, row)));
|
|
32880
|
-
}
|
|
32881
|
-
break;
|
|
32882
|
-
case "ADD_MERGE":
|
|
32883
|
-
case "REMOVE_MERGE":
|
|
32884
|
-
for (let target of cmd.target) {
|
|
32885
|
-
for (let row of range(target.top, target.bottom + 1)) {
|
|
32886
|
-
const rowHeight = this.getRowTallestCellSize(cmd.sheetId, row);
|
|
32887
|
-
if (rowHeight !== this.getRowSize(cmd.sheetId, row)) {
|
|
32888
|
-
this.history.update("sizes", cmd.sheetId, "ROW", row, "computedSize", lazy(rowHeight));
|
|
32889
|
-
}
|
|
33033
|
+
else {
|
|
33034
|
+
for (const el of cmd.elements) {
|
|
33035
|
+
this.history.update("sizes", cmd.sheetId, cmd.dimension, el, cmd.size || undefined);
|
|
32890
33036
|
}
|
|
32891
33037
|
}
|
|
32892
33038
|
break;
|
|
@@ -32894,94 +33040,29 @@ class HeaderSizePlugin extends CorePlugin {
|
|
|
32894
33040
|
return;
|
|
32895
33041
|
}
|
|
32896
33042
|
getColSize(sheetId, index) {
|
|
32897
|
-
return this.
|
|
32898
|
-
}
|
|
32899
|
-
getRowSize(sheetId, index) {
|
|
32900
|
-
return this.getHeaderSize(sheetId, "ROW", index);
|
|
33043
|
+
return Math.round(this.sizes[sheetId]?.["COL"][index] || DEFAULT_CELL_WIDTH);
|
|
32901
33044
|
}
|
|
32902
|
-
|
|
32903
|
-
|
|
32904
|
-
|
|
32905
|
-
this.getDefaultHeaderSize(dimension));
|
|
32906
|
-
}
|
|
32907
|
-
computeSheetSizes(sheetId) {
|
|
32908
|
-
const sizes = { COL: [], ROW: [] };
|
|
32909
|
-
for (let col of range(0, this.getters.getNumberCols(sheetId))) {
|
|
32910
|
-
sizes.COL.push(this.getHeaderSize(sheetId, "COL", col));
|
|
32911
|
-
}
|
|
32912
|
-
for (let row of range(0, this.getters.getNumberRows(sheetId))) {
|
|
32913
|
-
let rowSize = this.sizes[sheetId]?.["ROW"]?.[row].manualSize;
|
|
32914
|
-
if (!rowSize) {
|
|
32915
|
-
const height = this.getRowTallestCellSize(sheetId, row);
|
|
32916
|
-
rowSize = height;
|
|
32917
|
-
}
|
|
32918
|
-
sizes.ROW.push(rowSize);
|
|
32919
|
-
}
|
|
32920
|
-
return sizes;
|
|
32921
|
-
}
|
|
32922
|
-
getDefaultHeaderSize(dimension) {
|
|
32923
|
-
return dimension === "COL" ? DEFAULT_CELL_WIDTH : DEFAULT_CELL_HEIGHT;
|
|
32924
|
-
}
|
|
32925
|
-
/**
|
|
32926
|
-
* Return the height the cell should have in the sheet, which is either DEFAULT_CELL_HEIGHT if the cell is in a multi-row
|
|
32927
|
-
* merge, or the height of the cell computed based on its font size.
|
|
32928
|
-
*/
|
|
32929
|
-
getCellHeight(position) {
|
|
32930
|
-
const merge = this.getters.getMerge(position);
|
|
32931
|
-
if (merge && merge.bottom !== merge.top) {
|
|
32932
|
-
return DEFAULT_CELL_HEIGHT;
|
|
32933
|
-
}
|
|
32934
|
-
const cell = this.getters.getCell(position);
|
|
32935
|
-
return getDefaultCellHeight(cell);
|
|
32936
|
-
}
|
|
32937
|
-
/**
|
|
32938
|
-
* Get the tallest cell of a row and its size.
|
|
32939
|
-
*
|
|
32940
|
-
* The tallest cell of the row correspond to the cell with the biggest font size,
|
|
32941
|
-
* and that is not part of a multi-line merge.
|
|
32942
|
-
*/
|
|
32943
|
-
getRowTallestCellSize(sheetId, row) {
|
|
32944
|
-
const cellIds = this.getters.getRowCells(sheetId, row);
|
|
32945
|
-
let maxHeight = 0;
|
|
32946
|
-
for (let i = 0; i < cellIds.length; i++) {
|
|
32947
|
-
const cell = this.getters.getCellById(cellIds[i]);
|
|
32948
|
-
if (!cell)
|
|
32949
|
-
continue;
|
|
32950
|
-
const position = this.getters.getCellPosition(cell.id);
|
|
32951
|
-
const cellHeight = this.getCellHeight(position);
|
|
32952
|
-
if (cellHeight > maxHeight && cellHeight > DEFAULT_CELL_HEIGHT) {
|
|
32953
|
-
maxHeight = cellHeight;
|
|
32954
|
-
}
|
|
32955
|
-
}
|
|
32956
|
-
if (maxHeight <= DEFAULT_CELL_HEIGHT) {
|
|
32957
|
-
return DEFAULT_CELL_HEIGHT;
|
|
32958
|
-
}
|
|
32959
|
-
return maxHeight;
|
|
33045
|
+
getUserRowSize(sheetId, index) {
|
|
33046
|
+
const rowSize = this.sizes[sheetId]?.["ROW"][index];
|
|
33047
|
+
return rowSize ? Math.round(rowSize) : undefined;
|
|
32960
33048
|
}
|
|
32961
33049
|
import(data) {
|
|
32962
33050
|
for (let sheet of data.sheets) {
|
|
32963
|
-
const
|
|
33051
|
+
const sizes = {
|
|
33052
|
+
COL: Array(sheet.colNumber).fill(undefined),
|
|
33053
|
+
ROW: Array(sheet.rowNumber).fill(undefined),
|
|
33054
|
+
};
|
|
32964
33055
|
for (let [rowIndex, row] of Object.entries(sheet.rows)) {
|
|
32965
33056
|
if (row.size) {
|
|
32966
|
-
|
|
33057
|
+
sizes["ROW"][rowIndex] = row.size;
|
|
32967
33058
|
}
|
|
32968
33059
|
}
|
|
32969
33060
|
for (let [colIndex, col] of Object.entries(sheet.cols)) {
|
|
32970
33061
|
if (col.size) {
|
|
32971
|
-
|
|
32972
|
-
}
|
|
32973
|
-
}
|
|
32974
|
-
|
|
32975
|
-
this.sizes[sheet.id] = {
|
|
32976
|
-
COL: computedSizes.COL.map((size, i) => ({
|
|
32977
|
-
manualSize: manualSizes.COL[i],
|
|
32978
|
-
computedSize: lazy(size),
|
|
32979
|
-
})),
|
|
32980
|
-
ROW: computedSizes.ROW.map((size, i) => ({
|
|
32981
|
-
manualSize: manualSizes.ROW[i],
|
|
32982
|
-
computedSize: lazy(size),
|
|
32983
|
-
})),
|
|
32984
|
-
};
|
|
33062
|
+
sizes["COL"][colIndex] = col.size;
|
|
33063
|
+
}
|
|
33064
|
+
}
|
|
33065
|
+
this.sizes[sheet.id] = sizes;
|
|
32985
33066
|
}
|
|
32986
33067
|
return;
|
|
32987
33068
|
}
|
|
@@ -33002,9 +33083,12 @@ class HeaderSizePlugin extends CorePlugin {
|
|
|
33002
33083
|
if (sheet.rows === undefined) {
|
|
33003
33084
|
sheet.rows = {};
|
|
33004
33085
|
}
|
|
33005
|
-
for (
|
|
33006
|
-
if (exportDefaults || this.sizes[sheet.id]["ROW"][row]
|
|
33007
|
-
sheet.rows[row] = {
|
|
33086
|
+
for (const row of range(0, this.getters.getNumberRows(sheet.id))) {
|
|
33087
|
+
if (exportDefaults || this.sizes[sheet.id]["ROW"][row]) {
|
|
33088
|
+
sheet.rows[row] = {
|
|
33089
|
+
...sheet.rows[row],
|
|
33090
|
+
size: this.getUserRowSize(sheet.id, row) ?? DEFAULT_CELL_HEIGHT,
|
|
33091
|
+
};
|
|
33008
33092
|
}
|
|
33009
33093
|
}
|
|
33010
33094
|
// Export col sizes
|
|
@@ -33012,7 +33096,7 @@ class HeaderSizePlugin extends CorePlugin {
|
|
|
33012
33096
|
sheet.cols = {};
|
|
33013
33097
|
}
|
|
33014
33098
|
for (let col of range(0, this.getters.getNumberCols(sheet.id))) {
|
|
33015
|
-
if (exportDefaults || this.sizes[sheet.id]["COL"][col]
|
|
33099
|
+
if (exportDefaults || this.sizes[sheet.id]["COL"][col]) {
|
|
33016
33100
|
sheet.cols[col] = { ...sheet.cols[col], size: this.getColSize(sheet.id, col) };
|
|
33017
33101
|
}
|
|
33018
33102
|
}
|
|
@@ -36568,7 +36652,7 @@ class EvaluationConditionalFormatPlugin extends UIPlugin {
|
|
|
36568
36652
|
case "ContainsText":
|
|
36569
36653
|
return cell.value.toString().indexOf(values[0].toString()) > -1;
|
|
36570
36654
|
case "NotContains":
|
|
36571
|
-
return !cell.value || cell.value.toString().indexOf(values[0].toString())
|
|
36655
|
+
return !cell.value || cell.value.toString().indexOf(values[0].toString()) === -1;
|
|
36572
36656
|
case "GreaterThan":
|
|
36573
36657
|
return cell.value > values[0];
|
|
36574
36658
|
case "GreaterThanOrEqual":
|
|
@@ -36595,6 +36679,156 @@ class EvaluationConditionalFormatPlugin extends UIPlugin {
|
|
|
36595
36679
|
};
|
|
36596
36680
|
}
|
|
36597
36681
|
|
|
36682
|
+
class UIRowSizePlugin extends UIPlugin {
|
|
36683
|
+
static getters = ["getRowSize"];
|
|
36684
|
+
tallestCellInRow = {};
|
|
36685
|
+
ctx = document.createElement("canvas").getContext("2d");
|
|
36686
|
+
handle(cmd) {
|
|
36687
|
+
switch (cmd.type) {
|
|
36688
|
+
case "START":
|
|
36689
|
+
for (const sheetId of this.getters.getSheetIds()) {
|
|
36690
|
+
this.initializeSheet(sheetId);
|
|
36691
|
+
}
|
|
36692
|
+
break;
|
|
36693
|
+
case "CREATE_SHEET": {
|
|
36694
|
+
this.initializeSheet(cmd.sheetId);
|
|
36695
|
+
break;
|
|
36696
|
+
}
|
|
36697
|
+
case "DUPLICATE_SHEET": {
|
|
36698
|
+
const tallestCells = deepCopy(this.tallestCellInRow[cmd.sheetId]);
|
|
36699
|
+
this.history.update("tallestCellInRow", cmd.sheetIdTo, tallestCells);
|
|
36700
|
+
break;
|
|
36701
|
+
}
|
|
36702
|
+
case "DELETE_SHEET":
|
|
36703
|
+
const tallestCells = { ...this.tallestCellInRow };
|
|
36704
|
+
delete tallestCells[cmd.sheetId];
|
|
36705
|
+
this.history.update("tallestCellInRow", tallestCells);
|
|
36706
|
+
break;
|
|
36707
|
+
case "REMOVE_COLUMNS_ROWS": {
|
|
36708
|
+
if (cmd.dimension === "COL") {
|
|
36709
|
+
return;
|
|
36710
|
+
}
|
|
36711
|
+
const tallestCells = removeIndexesFromArray(this.tallestCellInRow[cmd.sheetId], cmd.elements);
|
|
36712
|
+
this.history.update("tallestCellInRow", cmd.sheetId, tallestCells);
|
|
36713
|
+
break;
|
|
36714
|
+
}
|
|
36715
|
+
case "ADD_COLUMNS_ROWS": {
|
|
36716
|
+
if (cmd.dimension === "COL") {
|
|
36717
|
+
return;
|
|
36718
|
+
}
|
|
36719
|
+
const addIndex = getAddHeaderStartIndex(cmd.position, cmd.base);
|
|
36720
|
+
const newCells = Array(cmd.quantity).fill(undefined);
|
|
36721
|
+
const newTallestCells = insertItemsAtIndex(this.tallestCellInRow[cmd.sheetId], newCells, addIndex);
|
|
36722
|
+
this.history.update("tallestCellInRow", cmd.sheetId, newTallestCells);
|
|
36723
|
+
break;
|
|
36724
|
+
}
|
|
36725
|
+
case "RESIZE_COLUMNS_ROWS":
|
|
36726
|
+
{
|
|
36727
|
+
const sheetId = cmd.sheetId;
|
|
36728
|
+
if (cmd.dimension === "ROW") {
|
|
36729
|
+
for (const row of cmd.elements) {
|
|
36730
|
+
const tallestCell = this.getRowTallestCell(sheetId, row);
|
|
36731
|
+
this.history.update("tallestCellInRow", sheetId, row, tallestCell);
|
|
36732
|
+
}
|
|
36733
|
+
}
|
|
36734
|
+
else {
|
|
36735
|
+
// Recompute row heights on col size change, they might have changed because of wrapped text
|
|
36736
|
+
for (const row of range(0, this.getters.getNumberRows(sheetId))) {
|
|
36737
|
+
for (const col of cmd.elements) {
|
|
36738
|
+
this.updateRowSizeForCellChange(sheetId, row, col);
|
|
36739
|
+
}
|
|
36740
|
+
}
|
|
36741
|
+
}
|
|
36742
|
+
}
|
|
36743
|
+
break;
|
|
36744
|
+
case "UPDATE_CELL":
|
|
36745
|
+
this.updateRowSizeForCellChange(cmd.sheetId, cmd.row, cmd.col);
|
|
36746
|
+
break;
|
|
36747
|
+
case "ADD_MERGE":
|
|
36748
|
+
case "REMOVE_MERGE":
|
|
36749
|
+
for (const target of cmd.target) {
|
|
36750
|
+
for (const position of positions(target)) {
|
|
36751
|
+
this.updateRowSizeForCellChange(cmd.sheetId, position.row, position.col);
|
|
36752
|
+
}
|
|
36753
|
+
}
|
|
36754
|
+
}
|
|
36755
|
+
return;
|
|
36756
|
+
}
|
|
36757
|
+
getRowSize(sheetId, row) {
|
|
36758
|
+
return Math.round(this.getters.getUserRowSize(sheetId, row) ??
|
|
36759
|
+
this.tallestCellInRow[sheetId][row]?.size ??
|
|
36760
|
+
DEFAULT_CELL_HEIGHT);
|
|
36761
|
+
}
|
|
36762
|
+
updateRowSizeForCellChange(sheetId, row, col) {
|
|
36763
|
+
const tallestCellInRow = this.tallestCellInRow[sheetId]?.[row];
|
|
36764
|
+
if (tallestCellInRow?.cell.col === col) {
|
|
36765
|
+
const newTallestCell = this.getRowTallestCell(sheetId, row);
|
|
36766
|
+
this.history.update("tallestCellInRow", sheetId, row, newTallestCell);
|
|
36767
|
+
}
|
|
36768
|
+
const updatedCellHeight = this.getCellHeight({ sheetId, col, row });
|
|
36769
|
+
if (updatedCellHeight <= DEFAULT_CELL_HEIGHT) {
|
|
36770
|
+
return;
|
|
36771
|
+
}
|
|
36772
|
+
if ((!tallestCellInRow && updatedCellHeight > DEFAULT_CELL_HEIGHT) ||
|
|
36773
|
+
(tallestCellInRow && updatedCellHeight > tallestCellInRow.size)) {
|
|
36774
|
+
const newTallestCell = { cell: { sheetId, col, row }, size: updatedCellHeight };
|
|
36775
|
+
this.history.update("tallestCellInRow", sheetId, row, newTallestCell);
|
|
36776
|
+
}
|
|
36777
|
+
}
|
|
36778
|
+
initializeSheet(sheetId) {
|
|
36779
|
+
const tallestCells = [];
|
|
36780
|
+
for (let row = 0; row < this.getters.getNumberRows(sheetId); row++) {
|
|
36781
|
+
const tallestCell = this.getRowTallestCell(sheetId, row);
|
|
36782
|
+
tallestCells.push(tallestCell);
|
|
36783
|
+
}
|
|
36784
|
+
this.history.update("tallestCellInRow", sheetId, tallestCells);
|
|
36785
|
+
}
|
|
36786
|
+
/**
|
|
36787
|
+
* Return the height the cell should have in the sheet, which is either DEFAULT_CELL_HEIGHT if the cell is in a multi-row
|
|
36788
|
+
* merge, or the height of the cell computed based on its style/content.
|
|
36789
|
+
*/
|
|
36790
|
+
getCellHeight(position) {
|
|
36791
|
+
if (this.isInMultiRowMerge(position)) {
|
|
36792
|
+
return DEFAULT_CELL_HEIGHT;
|
|
36793
|
+
}
|
|
36794
|
+
const cell = this.getters.getCell(position);
|
|
36795
|
+
const colSize = this.getters.getColSize(position.sheetId, position.col);
|
|
36796
|
+
return getDefaultCellHeight(this.ctx, cell, colSize);
|
|
36797
|
+
}
|
|
36798
|
+
isInMultiRowMerge(position) {
|
|
36799
|
+
const merge = this.getters.getMerge(position);
|
|
36800
|
+
return !!merge && merge.bottom !== merge.top;
|
|
36801
|
+
}
|
|
36802
|
+
/**
|
|
36803
|
+
* Get the tallest cell of a row and its size.
|
|
36804
|
+
*/
|
|
36805
|
+
getRowTallestCell(sheetId, row) {
|
|
36806
|
+
const userRowSize = this.getters.getUserRowSize(sheetId, row);
|
|
36807
|
+
if (userRowSize !== undefined) {
|
|
36808
|
+
return undefined;
|
|
36809
|
+
}
|
|
36810
|
+
const cellIds = this.getters.getRowCells(sheetId, row);
|
|
36811
|
+
let maxHeight = 0;
|
|
36812
|
+
let tallestCell = undefined;
|
|
36813
|
+
for (let i = 0; i < cellIds.length; i++) {
|
|
36814
|
+
const cell = this.getters.getCellById(cellIds[i]);
|
|
36815
|
+
if (!cell) {
|
|
36816
|
+
continue;
|
|
36817
|
+
}
|
|
36818
|
+
const position = this.getters.getCellPosition(cell.id);
|
|
36819
|
+
const cellHeight = this.getCellHeight(position);
|
|
36820
|
+
if (cellHeight > maxHeight && cellHeight > DEFAULT_CELL_HEIGHT) {
|
|
36821
|
+
maxHeight = cellHeight;
|
|
36822
|
+
tallestCell = { cell: position, size: cellHeight };
|
|
36823
|
+
}
|
|
36824
|
+
}
|
|
36825
|
+
if (tallestCell && tallestCell.size > DEFAULT_CELL_HEIGHT) {
|
|
36826
|
+
return tallestCell;
|
|
36827
|
+
}
|
|
36828
|
+
return undefined;
|
|
36829
|
+
}
|
|
36830
|
+
}
|
|
36831
|
+
|
|
36598
36832
|
/**
|
|
36599
36833
|
* This plugin manage the autofill.
|
|
36600
36834
|
*
|
|
@@ -40028,10 +40262,8 @@ class SortPlugin extends UIPlugin {
|
|
|
40028
40262
|
}
|
|
40029
40263
|
updateCellCommands.push(newCellValues);
|
|
40030
40264
|
}
|
|
40031
|
-
for (const cmd of updateCellCommands) {
|
|
40032
|
-
this.dispatch("UPDATE_CELL", cmd);
|
|
40033
|
-
}
|
|
40034
40265
|
}
|
|
40266
|
+
updateCellCommands.forEach((cmdPayload) => this.dispatch("UPDATE_CELL", cmdPayload));
|
|
40035
40267
|
}
|
|
40036
40268
|
/**
|
|
40037
40269
|
* Return the distances between main merge cells in the zone.
|
|
@@ -40132,24 +40364,28 @@ class SheetUIPlugin extends UIPlugin {
|
|
|
40132
40364
|
// Getters
|
|
40133
40365
|
// ---------------------------------------------------------------------------
|
|
40134
40366
|
getCellWidth(position) {
|
|
40135
|
-
const text = this.getCellText(position);
|
|
40136
40367
|
const style = this.getters.getCellComputedStyle(position);
|
|
40137
|
-
|
|
40138
|
-
|
|
40368
|
+
let contentWidth = 0;
|
|
40369
|
+
const content = this.getters.getEvaluatedCell(position).formattedValue;
|
|
40370
|
+
if (content) {
|
|
40371
|
+
const multiLineText = splitTextToWidth(this.ctx, content, style, undefined);
|
|
40372
|
+
contentWidth += Math.max(...multiLineText.map((line) => computeTextWidth(this.ctx, line, style)));
|
|
40373
|
+
}
|
|
40139
40374
|
const icon = this.getters.getConditionalIcon(position);
|
|
40140
40375
|
if (icon) {
|
|
40141
|
-
contentWidth += computeIconWidth(
|
|
40376
|
+
contentWidth += computeIconWidth(style);
|
|
40142
40377
|
}
|
|
40143
40378
|
const isFilterHeader = this.getters.isFilterHeader(position);
|
|
40144
40379
|
if (isFilterHeader) {
|
|
40145
40380
|
contentWidth += ICON_EDGE_LENGTH + FILTER_ICON_MARGIN;
|
|
40146
40381
|
}
|
|
40147
|
-
if (contentWidth
|
|
40148
|
-
|
|
40149
|
-
|
|
40150
|
-
|
|
40151
|
-
|
|
40152
|
-
|
|
40382
|
+
if (contentWidth === 0) {
|
|
40383
|
+
return 0;
|
|
40384
|
+
}
|
|
40385
|
+
contentWidth += 2 * PADDING_AUTORESIZE_HORIZONTAL;
|
|
40386
|
+
if (style.wrapping === "wrap") {
|
|
40387
|
+
const colWidth = this.getters.getColSize(this.getters.getActiveSheetId(), position.col);
|
|
40388
|
+
return Math.min(colWidth, contentWidth);
|
|
40153
40389
|
}
|
|
40154
40390
|
return contentWidth;
|
|
40155
40391
|
}
|
|
@@ -40172,56 +40408,7 @@ class SheetUIPlugin extends UIPlugin {
|
|
|
40172
40408
|
getCellMultiLineText(position, width) {
|
|
40173
40409
|
const style = this.getters.getCellStyle(position);
|
|
40174
40410
|
const text = this.getters.getCellText(position, this.getters.shouldShowFormulas());
|
|
40175
|
-
|
|
40176
|
-
for (const line of text.split("\n")) {
|
|
40177
|
-
const words = line.split(" ");
|
|
40178
|
-
if (!width) {
|
|
40179
|
-
brokenText.push(line);
|
|
40180
|
-
continue;
|
|
40181
|
-
}
|
|
40182
|
-
let textLine = "";
|
|
40183
|
-
let availableWidth = width;
|
|
40184
|
-
for (let word of words) {
|
|
40185
|
-
const splitWord = this.splitWordToSpecificWidth(this.ctx, word, width, style);
|
|
40186
|
-
const lastPart = splitWord.pop();
|
|
40187
|
-
const lastPartWidth = computeTextWidth(this.ctx, lastPart, style);
|
|
40188
|
-
// At this step: "splitWord" is an array composed of parts of word whose
|
|
40189
|
-
// length is at most equal to "width".
|
|
40190
|
-
// Last part contains the end of the word.
|
|
40191
|
-
// Note that: When word length is less than width, then lastPart is equal
|
|
40192
|
-
// to word and splitWord is empty
|
|
40193
|
-
if (splitWord.length) {
|
|
40194
|
-
if (textLine !== "") {
|
|
40195
|
-
brokenText.push(textLine);
|
|
40196
|
-
textLine = "";
|
|
40197
|
-
availableWidth = width;
|
|
40198
|
-
}
|
|
40199
|
-
splitWord.forEach((wordPart) => {
|
|
40200
|
-
brokenText.push(wordPart);
|
|
40201
|
-
});
|
|
40202
|
-
textLine = lastPart;
|
|
40203
|
-
availableWidth = width - lastPartWidth;
|
|
40204
|
-
}
|
|
40205
|
-
else {
|
|
40206
|
-
// here "lastPart" is equal to "word" and the "word" size is smaller than "width"
|
|
40207
|
-
const _word = textLine === "" ? lastPart : " " + lastPart;
|
|
40208
|
-
const wordWidth = computeTextWidth(this.ctx, _word, style);
|
|
40209
|
-
if (wordWidth <= availableWidth) {
|
|
40210
|
-
textLine += _word;
|
|
40211
|
-
availableWidth -= wordWidth;
|
|
40212
|
-
}
|
|
40213
|
-
else {
|
|
40214
|
-
brokenText.push(textLine);
|
|
40215
|
-
textLine = lastPart;
|
|
40216
|
-
availableWidth = width - lastPartWidth;
|
|
40217
|
-
}
|
|
40218
|
-
}
|
|
40219
|
-
}
|
|
40220
|
-
if (textLine !== "") {
|
|
40221
|
-
brokenText.push(textLine);
|
|
40222
|
-
}
|
|
40223
|
-
}
|
|
40224
|
-
return brokenText;
|
|
40411
|
+
return splitTextToWidth(this.ctx, text, style, width);
|
|
40225
40412
|
}
|
|
40226
40413
|
/**
|
|
40227
40414
|
* Returns the size, start and end coordinates of a column on an unfolded sheet
|
|
@@ -40280,26 +40467,6 @@ class SheetUIPlugin extends UIPlugin {
|
|
|
40280
40467
|
const sizes = cellsPositions.map((position) => this.getCellWidth({ sheetId, ...position }));
|
|
40281
40468
|
return Math.max(0, ...sizes);
|
|
40282
40469
|
}
|
|
40283
|
-
splitWordToSpecificWidth(ctx, word, width, style) {
|
|
40284
|
-
const wordWidth = computeTextWidth(ctx, word, style);
|
|
40285
|
-
if (wordWidth <= width) {
|
|
40286
|
-
return [word];
|
|
40287
|
-
}
|
|
40288
|
-
const splitWord = [];
|
|
40289
|
-
let wordPart = "";
|
|
40290
|
-
for (let l of word) {
|
|
40291
|
-
const wordPartWidth = computeTextWidth(ctx, wordPart + l, style);
|
|
40292
|
-
if (wordPartWidth > width) {
|
|
40293
|
-
splitWord.push(wordPart);
|
|
40294
|
-
wordPart = l;
|
|
40295
|
-
}
|
|
40296
|
-
else {
|
|
40297
|
-
wordPart += l;
|
|
40298
|
-
}
|
|
40299
|
-
}
|
|
40300
|
-
splitWord.push(wordPart);
|
|
40301
|
-
return splitWord;
|
|
40302
|
-
}
|
|
40303
40470
|
/**
|
|
40304
40471
|
* Check that any "sheetId" in the command matches an existing
|
|
40305
40472
|
* sheet.
|
|
@@ -41291,7 +41458,7 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
|
|
|
41291
41458
|
.join("\n") || "\t");
|
|
41292
41459
|
}
|
|
41293
41460
|
getHTMLContent() {
|
|
41294
|
-
if (this.cells.length
|
|
41461
|
+
if (this.cells.length === 1 && this.cells[0].length === 1) {
|
|
41295
41462
|
return this.getters.getCellText(this.cells[0][0].position);
|
|
41296
41463
|
}
|
|
41297
41464
|
let htmlTable = '<table border="1" style="border-collapse:collapse">';
|
|
@@ -41616,7 +41783,7 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
41616
41783
|
status = "invisible";
|
|
41617
41784
|
state;
|
|
41618
41785
|
lastPasteState;
|
|
41619
|
-
|
|
41786
|
+
paintFormatStatus = "inactive";
|
|
41620
41787
|
originSheetId;
|
|
41621
41788
|
// ---------------------------------------------------------------------------
|
|
41622
41789
|
// Command Handling
|
|
@@ -41631,7 +41798,7 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
41631
41798
|
if (!this.state) {
|
|
41632
41799
|
return 24 /* CommandResult.EmptyClipboard */;
|
|
41633
41800
|
}
|
|
41634
|
-
const pasteOption = cmd.pasteOption || (this.
|
|
41801
|
+
const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
|
|
41635
41802
|
return this.state.isPasteAllowed(cmd.target, { pasteOption });
|
|
41636
41803
|
case "PASTE_FROM_OS_CLIPBOARD": {
|
|
41637
41804
|
const state = new ClipboardOsState(cmd.text, this.getters, this.dispatch, this.selection);
|
|
@@ -41647,6 +41814,11 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
41647
41814
|
const state = this.getClipboardStateForCopyCells(cut, "CUT");
|
|
41648
41815
|
return state.isPasteAllowed(paste);
|
|
41649
41816
|
}
|
|
41817
|
+
case "ACTIVATE_PAINT_FORMAT": {
|
|
41818
|
+
if (this.paintFormatStatus !== "inactive") {
|
|
41819
|
+
return 95 /* CommandResult.AlreadyInPaintingFormatMode */;
|
|
41820
|
+
}
|
|
41821
|
+
}
|
|
41650
41822
|
}
|
|
41651
41823
|
return 0 /* CommandResult.Success */;
|
|
41652
41824
|
}
|
|
@@ -41663,11 +41835,13 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
41663
41835
|
if (!this.state) {
|
|
41664
41836
|
break;
|
|
41665
41837
|
}
|
|
41666
|
-
const pasteOption = cmd.pasteOption || (this.
|
|
41667
|
-
this._isPaintingFormat = false;
|
|
41838
|
+
const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
|
|
41668
41839
|
this.state.paste(cmd.target, { pasteOption, shouldPasteCF: true, selectTarget: true });
|
|
41669
41840
|
this.lastPasteState = this.state;
|
|
41670
|
-
this.
|
|
41841
|
+
if (this.paintFormatStatus === "oneOff") {
|
|
41842
|
+
this.paintFormatStatus = "inactive";
|
|
41843
|
+
this.status = "invisible";
|
|
41844
|
+
}
|
|
41671
41845
|
break;
|
|
41672
41846
|
case "CLEAN_CLIPBOARD_HIGHLIGHT":
|
|
41673
41847
|
this.status = "invisible";
|
|
@@ -41735,8 +41909,13 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
41735
41909
|
case "ACTIVATE_PAINT_FORMAT": {
|
|
41736
41910
|
const zones = this.getters.getSelectedZones();
|
|
41737
41911
|
this.state = this.getClipboardStateForCopyCells(zones, "COPY");
|
|
41738
|
-
this._isPaintingFormat = true;
|
|
41739
41912
|
this.status = "visible";
|
|
41913
|
+
if (cmd.persistent) {
|
|
41914
|
+
this.paintFormatStatus = "persistent";
|
|
41915
|
+
}
|
|
41916
|
+
else {
|
|
41917
|
+
this.paintFormatStatus = "oneOff";
|
|
41918
|
+
}
|
|
41740
41919
|
break;
|
|
41741
41920
|
}
|
|
41742
41921
|
case "DELETE_SHEET":
|
|
@@ -41748,6 +41927,11 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
41748
41927
|
this.status = "invisible";
|
|
41749
41928
|
}
|
|
41750
41929
|
break;
|
|
41930
|
+
case "CANCEL_PAINT_FORMAT": {
|
|
41931
|
+
this.paintFormatStatus = "inactive";
|
|
41932
|
+
this.status = "invisible";
|
|
41933
|
+
break;
|
|
41934
|
+
}
|
|
41751
41935
|
default:
|
|
41752
41936
|
if (isCoreCommand(cmd)) {
|
|
41753
41937
|
this.status = "invisible";
|
|
@@ -41778,7 +41962,7 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
41778
41962
|
return this.state ? this.state.operation === "CUT" : false;
|
|
41779
41963
|
}
|
|
41780
41964
|
isPaintingFormat() {
|
|
41781
|
-
return this.
|
|
41965
|
+
return this.paintFormatStatus !== "inactive";
|
|
41782
41966
|
}
|
|
41783
41967
|
// ---------------------------------------------------------------------------
|
|
41784
41968
|
// Private methods
|
|
@@ -44413,6 +44597,7 @@ const coreViewsPluginRegistry = new Registry()
|
|
|
44413
44597
|
.add("evaluation", EvaluationPlugin)
|
|
44414
44598
|
.add("evaluation_chart", EvaluationChartPlugin)
|
|
44415
44599
|
.add("evaluation_cf", EvaluationConditionalFormatPlugin)
|
|
44600
|
+
.add("row_size", UIRowSizePlugin)
|
|
44416
44601
|
.add("custom_colors", CustomColorsPlugin);
|
|
44417
44602
|
|
|
44418
44603
|
const clickableCellRegistry = new Registry();
|
|
@@ -45668,11 +45853,11 @@ class ActionButton extends Component {
|
|
|
45668
45853
|
}
|
|
45669
45854
|
get title() {
|
|
45670
45855
|
const name = this.actionButton.name(this.env);
|
|
45671
|
-
const description = this.actionButton.description;
|
|
45856
|
+
const description = this.actionButton.description(this.env);
|
|
45672
45857
|
return name + (description ? ` (${description})` : "");
|
|
45673
45858
|
}
|
|
45674
45859
|
get iconTitle() {
|
|
45675
|
-
return this.actionButton.icon;
|
|
45860
|
+
return this.actionButton.icon(this.env);
|
|
45676
45861
|
}
|
|
45677
45862
|
onClick(ev) {
|
|
45678
45863
|
if (this.isEnabled) {
|
|
@@ -46057,6 +46242,27 @@ FontSizeEditor.props = {
|
|
|
46057
46242
|
class: String,
|
|
46058
46243
|
};
|
|
46059
46244
|
|
|
46245
|
+
class PaintFormatButton extends Component {
|
|
46246
|
+
static template = "o-spreadsheet-PaintFormatButton";
|
|
46247
|
+
get isActive() {
|
|
46248
|
+
return this.env.model.getters.isPaintingFormat();
|
|
46249
|
+
}
|
|
46250
|
+
onDblClick() {
|
|
46251
|
+
this.env.model.dispatch("ACTIVATE_PAINT_FORMAT", { persistent: true });
|
|
46252
|
+
}
|
|
46253
|
+
togglePaintFormat() {
|
|
46254
|
+
if (this.isActive) {
|
|
46255
|
+
this.env.model.dispatch("CANCEL_PAINT_FORMAT");
|
|
46256
|
+
}
|
|
46257
|
+
else {
|
|
46258
|
+
this.env.model.dispatch("ACTIVATE_PAINT_FORMAT", { persistent: false });
|
|
46259
|
+
}
|
|
46260
|
+
}
|
|
46261
|
+
}
|
|
46262
|
+
PaintFormatButton.props = {
|
|
46263
|
+
class: { type: String, optional: true },
|
|
46264
|
+
};
|
|
46265
|
+
|
|
46060
46266
|
// -----------------------------------------------------------------------------
|
|
46061
46267
|
// TopBar
|
|
46062
46268
|
// -----------------------------------------------------------------------------
|
|
@@ -46157,6 +46363,7 @@ class TopBar extends Component {
|
|
|
46157
46363
|
TopBarComposer,
|
|
46158
46364
|
FontSizeEditor,
|
|
46159
46365
|
ActionButton,
|
|
46366
|
+
PaintFormatButton,
|
|
46160
46367
|
BorderEditorWidget,
|
|
46161
46368
|
};
|
|
46162
46369
|
state = useState({
|
|
@@ -48009,7 +48216,7 @@ class SelectionStreamProcessorImpl {
|
|
|
48009
48216
|
: "nextCluster";
|
|
48010
48217
|
while (true) {
|
|
48011
48218
|
const nextCellPosition = this.getNextCellPosition(currentPosition, dim, dir);
|
|
48012
|
-
// Break if nextPosition
|
|
48219
|
+
// Break if nextPosition === currentPosition, which happens if there's no next valid position
|
|
48013
48220
|
if (currentPosition.col === nextCellPosition.col &&
|
|
48014
48221
|
currentPosition.row === nextCellPosition.row) {
|
|
48015
48222
|
break;
|
|
@@ -49923,6 +50130,7 @@ class Model extends EventBus {
|
|
|
49923
50130
|
...config,
|
|
49924
50131
|
mode: config.mode || "normal",
|
|
49925
50132
|
custom: config.custom || {},
|
|
50133
|
+
defaultCurrencyFormat: config.defaultCurrencyFormat || "[$$]#,##0.00",
|
|
49926
50134
|
external: this.setupExternalConfig(config.external || {}),
|
|
49927
50135
|
transportService,
|
|
49928
50136
|
client,
|
|
@@ -50220,6 +50428,7 @@ const helpers = {
|
|
|
50220
50428
|
numberToLetters,
|
|
50221
50429
|
UuidGenerator,
|
|
50222
50430
|
formatValue,
|
|
50431
|
+
createCurrencyFormat,
|
|
50223
50432
|
computeTextWidth,
|
|
50224
50433
|
createEmptyWorkbookData,
|
|
50225
50434
|
createEmptySheet,
|
|
@@ -50271,6 +50480,6 @@ const constants = {
|
|
|
50271
50480
|
export { AbstractChart, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, compile, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, tokenize };
|
|
50272
50481
|
|
|
50273
50482
|
|
|
50274
|
-
__info__.version = '16.
|
|
50275
|
-
__info__.date = '2023-07-
|
|
50276
|
-
__info__.hash = '
|
|
50483
|
+
__info__.version = '16.5.0-alpha.0';
|
|
50484
|
+
__info__.date = '2023-07-24T06:48:58.196Z';
|
|
50485
|
+
__info__.hash = '3ba2c3c';
|