@odoo/o-spreadsheet 16.4.0-alpha.7 → 16.4.1
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 +712 -491
- package/dist/o-spreadsheet.d.ts +142 -113
- package/dist/o-spreadsheet.esm.js +712 -491
- package/dist/o-spreadsheet.iife.js +712 -491
- package/dist/o-spreadsheet.iife.min.js +324 -315
- package/package.json +12 -12
|
@@ -108,8 +108,8 @@ const SELECTION_BORDER_COLOR = "#3266ca";
|
|
|
108
108
|
const HEADER_BORDER_COLOR = "#C0C0C0";
|
|
109
109
|
const CELL_BORDER_COLOR = "#E2E3E3";
|
|
110
110
|
const BACKGROUND_CHART_COLOR = "#FFFFFF";
|
|
111
|
-
const MENU_ITEM_DISABLED_COLOR = "#CACACA";
|
|
112
111
|
const BG_HOVER_COLOR = "#EBEBEB";
|
|
112
|
+
const DISABLED_TEXT_COLOR = "#CACACA";
|
|
113
113
|
const DEFAULT_COLOR_SCALE_MIDPOINT_COLOR = 0xb6d7a8;
|
|
114
114
|
const LINK_COLOR = "#01666b";
|
|
115
115
|
const FILTERS_COLOR = "#188038";
|
|
@@ -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
|
}
|
|
@@ -3926,7 +4051,6 @@ const readonlyAllowedCommands = new Set([
|
|
|
3926
4051
|
"SET_VIEWPORT_OFFSET",
|
|
3927
4052
|
"SELECT_SEARCH_NEXT_MATCH",
|
|
3928
4053
|
"SELECT_SEARCH_PREVIOUS_MATCH",
|
|
3929
|
-
"REFRESH_SEARCH",
|
|
3930
4054
|
"UPDATE_SEARCH",
|
|
3931
4055
|
"CLEAR_SEARCH",
|
|
3932
4056
|
"EVALUATE_CELLS",
|
|
@@ -4124,6 +4248,7 @@ var CommandResult;
|
|
|
4124
4248
|
CommandResult[CommandResult["NoSplitSeparatorInSelection"] = 92] = "NoSplitSeparatorInSelection";
|
|
4125
4249
|
CommandResult[CommandResult["NoActiveSheet"] = 93] = "NoActiveSheet";
|
|
4126
4250
|
CommandResult[CommandResult["InvalidLocale"] = 94] = "InvalidLocale";
|
|
4251
|
+
CommandResult[CommandResult["AlreadyInPaintingFormatMode"] = 95] = "AlreadyInPaintingFormatMode";
|
|
4127
4252
|
})(CommandResult || (CommandResult = {}));
|
|
4128
4253
|
|
|
4129
4254
|
const borderStyles = ["thin", "medium", "thick", "dashed", "dotted"];
|
|
@@ -5864,7 +5989,7 @@ css /* scss */ `
|
|
|
5864
5989
|
}
|
|
5865
5990
|
}
|
|
5866
5991
|
&.disabled {
|
|
5867
|
-
color: ${
|
|
5992
|
+
color: ${DISABLED_TEXT_COLOR};
|
|
5868
5993
|
cursor: not-allowed;
|
|
5869
5994
|
}
|
|
5870
5995
|
}
|
|
@@ -5939,8 +6064,8 @@ class Menu extends Component {
|
|
|
5939
6064
|
return this.props.menuItems.some((menuItem) => !!menuItem.icon || !!menuItem.isActive);
|
|
5940
6065
|
}
|
|
5941
6066
|
getIconName(menu) {
|
|
5942
|
-
if (menu.icon) {
|
|
5943
|
-
return menu.icon;
|
|
6067
|
+
if (menu.icon(this.env)) {
|
|
6068
|
+
return menu.icon(this.env);
|
|
5944
6069
|
}
|
|
5945
6070
|
if (menu.isActive?.(this.env)) {
|
|
5946
6071
|
return "o-spreadsheet-Icon.CHECK";
|
|
@@ -6374,7 +6499,7 @@ function invertMatrix(M) {
|
|
|
6374
6499
|
for (let pivot = 0; pivot < dim; pivot++) {
|
|
6375
6500
|
let diagonalElement = C[pivot][pivot];
|
|
6376
6501
|
// if we have a 0 on the diagonal we'll need to swap with a lower row
|
|
6377
|
-
if (diagonalElement
|
|
6502
|
+
if (diagonalElement === 0) {
|
|
6378
6503
|
//look through every row below the i'th row
|
|
6379
6504
|
for (let row = pivot + 1; row < dim; row++) {
|
|
6380
6505
|
//if the ii'th row has a non-0 in the i'th col, swap it with that row
|
|
@@ -6401,7 +6526,7 @@ function invertMatrix(M) {
|
|
|
6401
6526
|
// the other rows so that there will be 0's in this column in the
|
|
6402
6527
|
// rows above and below this one
|
|
6403
6528
|
for (let row = 0; row < dim; row++) {
|
|
6404
|
-
if (row
|
|
6529
|
+
if (row === pivot) {
|
|
6405
6530
|
continue;
|
|
6406
6531
|
}
|
|
6407
6532
|
// We want to change this element to 0
|
|
@@ -12466,7 +12591,7 @@ const ISNA = {
|
|
|
12466
12591
|
return false;
|
|
12467
12592
|
}
|
|
12468
12593
|
catch (e) {
|
|
12469
|
-
return e?.errorType
|
|
12594
|
+
return e?.errorType === CellErrorType.NotAvailable;
|
|
12470
12595
|
}
|
|
12471
12596
|
},
|
|
12472
12597
|
isExported: true,
|
|
@@ -15182,6 +15307,8 @@ const uuidGenerator$2 = new UuidGenerator();
|
|
|
15182
15307
|
function createAction(item) {
|
|
15183
15308
|
const name = item.name;
|
|
15184
15309
|
const children = item.children;
|
|
15310
|
+
const description = item.description;
|
|
15311
|
+
const icon = item.icon;
|
|
15185
15312
|
return {
|
|
15186
15313
|
id: item.id || uuidGenerator$2.uuidv4(),
|
|
15187
15314
|
name: typeof name === "function" ? name : () => name,
|
|
@@ -15199,8 +15326,8 @@ function createAction(item) {
|
|
|
15199
15326
|
: () => [],
|
|
15200
15327
|
isReadonlyAllowed: item.isReadonlyAllowed || false,
|
|
15201
15328
|
separator: item.separator || false,
|
|
15202
|
-
icon:
|
|
15203
|
-
description:
|
|
15329
|
+
icon: typeof icon === "function" ? icon : () => icon || "",
|
|
15330
|
+
description: typeof description === "function" ? description : () => description || "",
|
|
15204
15331
|
textColor: item.textColor,
|
|
15205
15332
|
sequence: item.sequence || 0,
|
|
15206
15333
|
};
|
|
@@ -16666,7 +16793,7 @@ function getChartTimeOptions(labels, labelFormat, locale) {
|
|
|
16666
16793
|
function convertDateFormatForMoment(format) {
|
|
16667
16794
|
format = format.replace(/y/g, "Y");
|
|
16668
16795
|
format = format.replace(/d/g, "D");
|
|
16669
|
-
// "m" before "h"
|
|
16796
|
+
// "m" before "h" === month, "m" after "h" === minute
|
|
16670
16797
|
const indexH = format.indexOf("h");
|
|
16671
16798
|
if (indexH >= 0) {
|
|
16672
16799
|
format = format.slice(0, indexH).replace(/m/g, "M") + format.slice(indexH);
|
|
@@ -17520,6 +17647,7 @@ function getChartMenu(figureId, onFigureDeleted, env) {
|
|
|
17520
17647
|
env.model.dispatch("SELECT_FIGURE", { id: figureId });
|
|
17521
17648
|
env.openSidePanel("ChartPanel");
|
|
17522
17649
|
},
|
|
17650
|
+
icon: "o-spreadsheet-Icon.EDIT",
|
|
17523
17651
|
},
|
|
17524
17652
|
getCopyMenuItem(figureId, env),
|
|
17525
17653
|
getCutMenuItem(figureId, env),
|
|
@@ -17551,6 +17679,7 @@ function getImageMenuRegistry(figureId, onFigureDeleted, env) {
|
|
|
17551
17679
|
width,
|
|
17552
17680
|
});
|
|
17553
17681
|
},
|
|
17682
|
+
icon: "o-spreadsheet-Icon.REFRESH",
|
|
17554
17683
|
},
|
|
17555
17684
|
getDeleteMenuItem(figureId, onFigureDeleted, env),
|
|
17556
17685
|
];
|
|
@@ -17567,6 +17696,7 @@ function getCopyMenuItem(figureId, env) {
|
|
|
17567
17696
|
env.model.dispatch("COPY");
|
|
17568
17697
|
await env.clipboard.write(env.model.getters.getClipboardContent());
|
|
17569
17698
|
},
|
|
17699
|
+
icon: "o-spreadsheet-Icon.COPY",
|
|
17570
17700
|
};
|
|
17571
17701
|
}
|
|
17572
17702
|
function getCutMenuItem(figureId, env) {
|
|
@@ -17580,6 +17710,7 @@ function getCutMenuItem(figureId, env) {
|
|
|
17580
17710
|
env.model.dispatch("CUT");
|
|
17581
17711
|
await env.clipboard.write(env.model.getters.getClipboardContent());
|
|
17582
17712
|
},
|
|
17713
|
+
icon: "o-spreadsheet-Icon.CUT",
|
|
17583
17714
|
};
|
|
17584
17715
|
}
|
|
17585
17716
|
function getDeleteMenuItem(figureId, onFigureDeleted, env) {
|
|
@@ -17594,6 +17725,7 @@ function getDeleteMenuItem(figureId, onFigureDeleted, env) {
|
|
|
17594
17725
|
});
|
|
17595
17726
|
onFigureDeleted();
|
|
17596
17727
|
},
|
|
17728
|
+
icon: "o-spreadsheet-Icon.DELETE",
|
|
17597
17729
|
};
|
|
17598
17730
|
}
|
|
17599
17731
|
|
|
@@ -18661,7 +18793,7 @@ const insertFunctionMin = {
|
|
|
18661
18793
|
};
|
|
18662
18794
|
const categorieFunctionAll = {
|
|
18663
18795
|
name: _lt("All"),
|
|
18664
|
-
children: allFunctionListMenuBuilder
|
|
18796
|
+
children: [allFunctionListMenuBuilder],
|
|
18665
18797
|
};
|
|
18666
18798
|
function allFunctionListMenuBuilder() {
|
|
18667
18799
|
const fnNames = functionRegistry.getKeys();
|
|
@@ -18993,7 +19125,10 @@ const formatNumberAutomatic = {
|
|
|
18993
19125
|
};
|
|
18994
19126
|
const formatNumberNumber = {
|
|
18995
19127
|
name: _lt("Number"),
|
|
18996
|
-
description:
|
|
19128
|
+
description: (env) => formatValue(1000.12, {
|
|
19129
|
+
format: "#,##0.00",
|
|
19130
|
+
locale: env.model.getters.getLocale(),
|
|
19131
|
+
}),
|
|
18997
19132
|
execute: (env) => setFormatter(env, "#,##0.00"),
|
|
18998
19133
|
isActive: (env) => isFormatSelected(env, "#,##0.00"),
|
|
18999
19134
|
};
|
|
@@ -19004,21 +19139,34 @@ const formatPercent = {
|
|
|
19004
19139
|
};
|
|
19005
19140
|
const formatNumberPercent = {
|
|
19006
19141
|
name: _lt("Percent"),
|
|
19007
|
-
description:
|
|
19142
|
+
description: (env) => formatValue(0.1012, {
|
|
19143
|
+
format: "0.00%",
|
|
19144
|
+
locale: env.model.getters.getLocale(),
|
|
19145
|
+
}),
|
|
19008
19146
|
execute: FORMAT_PERCENT_ACTION,
|
|
19009
19147
|
isActive: (env) => isFormatSelected(env, "0.00%"),
|
|
19010
19148
|
};
|
|
19011
19149
|
const formatNumberCurrency = {
|
|
19012
19150
|
name: _lt("Currency"),
|
|
19013
|
-
description:
|
|
19014
|
-
|
|
19015
|
-
|
|
19151
|
+
description: (env) => formatValue(1000.12, {
|
|
19152
|
+
format: env.model.config.defaultCurrencyFormat,
|
|
19153
|
+
locale: env.model.getters.getLocale(),
|
|
19154
|
+
}),
|
|
19155
|
+
execute: (env) => setFormatter(env, env.model.config.defaultCurrencyFormat),
|
|
19156
|
+
isActive: (env) => isFormatSelected(env, env.model.config.defaultCurrencyFormat),
|
|
19016
19157
|
};
|
|
19017
19158
|
const formatNumberCurrencyRounded = {
|
|
19018
19159
|
name: _lt("Currency rounded"),
|
|
19019
|
-
description:
|
|
19020
|
-
|
|
19021
|
-
|
|
19160
|
+
description: (env) => formatValue(1000, {
|
|
19161
|
+
format: roundFormat(env.model.config.defaultCurrencyFormat),
|
|
19162
|
+
locale: env.model.getters.getLocale(),
|
|
19163
|
+
}),
|
|
19164
|
+
execute: (env) => setFormatter(env, roundFormat(env.model.config.defaultCurrencyFormat)),
|
|
19165
|
+
isActive: (env) => isFormatSelected(env, roundFormat(env.model.config.defaultCurrencyFormat)),
|
|
19166
|
+
isVisible: (env) => {
|
|
19167
|
+
const currencyFormat = env.model.config.defaultCurrencyFormat;
|
|
19168
|
+
return currencyFormat !== roundFormat(currencyFormat);
|
|
19169
|
+
},
|
|
19022
19170
|
};
|
|
19023
19171
|
const formatCustomCurrency = {
|
|
19024
19172
|
name: _lt("Custom currency"),
|
|
@@ -19027,19 +19175,37 @@ const formatCustomCurrency = {
|
|
|
19027
19175
|
};
|
|
19028
19176
|
const formatNumberDate = {
|
|
19029
19177
|
name: _lt("Date"),
|
|
19030
|
-
description:
|
|
19178
|
+
description: (env) => {
|
|
19179
|
+
const locale = env.model.getters.getLocale();
|
|
19180
|
+
return formatValue(parseLiteral("9/26/2023", DEFAULT_LOCALE), {
|
|
19181
|
+
format: locale.dateFormat,
|
|
19182
|
+
locale,
|
|
19183
|
+
});
|
|
19184
|
+
},
|
|
19031
19185
|
execute: (env) => setFormatter(env, env.model.getters.getLocale().dateFormat),
|
|
19032
19186
|
isActive: (env) => isFormatSelected(env, env.model.getters.getLocale().dateFormat),
|
|
19033
19187
|
};
|
|
19034
19188
|
const formatNumberTime = {
|
|
19035
19189
|
name: _lt("Time"),
|
|
19036
|
-
description:
|
|
19190
|
+
description: (env) => {
|
|
19191
|
+
const locale = env.model.getters.getLocale();
|
|
19192
|
+
return formatValue(parseLiteral("9/26/2023 10:43:00 PM", DEFAULT_LOCALE), {
|
|
19193
|
+
format: locale.timeFormat,
|
|
19194
|
+
locale,
|
|
19195
|
+
});
|
|
19196
|
+
},
|
|
19037
19197
|
execute: (env) => setFormatter(env, env.model.getters.getLocale().timeFormat),
|
|
19038
19198
|
isActive: (env) => isFormatSelected(env, env.model.getters.getLocale().timeFormat),
|
|
19039
19199
|
};
|
|
19040
19200
|
const formatNumberDateTime = {
|
|
19041
19201
|
name: _lt("Date time"),
|
|
19042
|
-
description:
|
|
19202
|
+
description: (env) => {
|
|
19203
|
+
const locale = env.model.getters.getLocale();
|
|
19204
|
+
return formatValue(parseLiteral("9/26/2023 22:43:00", DEFAULT_LOCALE), {
|
|
19205
|
+
format: locale.dateFormat + " " + locale.timeFormat,
|
|
19206
|
+
locale,
|
|
19207
|
+
});
|
|
19208
|
+
},
|
|
19043
19209
|
execute: (env) => {
|
|
19044
19210
|
const locale = env.model.getters.getLocale();
|
|
19045
19211
|
setFormatter(env, locale.dateFormat + " " + locale.timeFormat);
|
|
@@ -19111,7 +19277,7 @@ const formatAlignment = {
|
|
|
19111
19277
|
};
|
|
19112
19278
|
const formatAlignmentHorizontal = {
|
|
19113
19279
|
name: _lt("Horizontal align"),
|
|
19114
|
-
icon:
|
|
19280
|
+
icon: (env) => getHorizontalAlignmentIcon(env),
|
|
19115
19281
|
};
|
|
19116
19282
|
const formatAlignmentLeft = {
|
|
19117
19283
|
name: _lt("Left"),
|
|
@@ -19136,46 +19302,50 @@ const formatAlignmentRight = {
|
|
|
19136
19302
|
};
|
|
19137
19303
|
const formatAlignmentVertical = {
|
|
19138
19304
|
name: _lt("Vertical align"),
|
|
19139
|
-
icon:
|
|
19305
|
+
icon: (env) => getVerticalAlignmentIcon(env),
|
|
19140
19306
|
};
|
|
19141
19307
|
const formatAlignmentTop = {
|
|
19142
19308
|
name: _lt("Top"),
|
|
19143
19309
|
execute: (env) => setStyle(env, { verticalAlign: "top" }),
|
|
19144
|
-
isActive: (env) => (env
|
|
19310
|
+
isActive: (env) => getVerticalAlign(env) === "top",
|
|
19145
19311
|
icon: "o-spreadsheet-Icon.ALIGN_TOP",
|
|
19146
19312
|
};
|
|
19147
19313
|
const formatAlignmentMiddle = {
|
|
19148
19314
|
name: _lt("Middle"),
|
|
19149
19315
|
execute: (env) => setStyle(env, { verticalAlign: "middle" }),
|
|
19150
|
-
isActive: (env) => (env
|
|
19316
|
+
isActive: (env) => getVerticalAlign(env) === "middle",
|
|
19151
19317
|
icon: "o-spreadsheet-Icon.ALIGN_MIDDLE",
|
|
19152
19318
|
};
|
|
19153
19319
|
const formatAlignmentBottom = {
|
|
19154
19320
|
name: _lt("Bottom"),
|
|
19155
19321
|
execute: (env) => setStyle(env, { verticalAlign: "bottom" }),
|
|
19156
|
-
isActive: (env) => (env
|
|
19322
|
+
isActive: (env) => getVerticalAlign(env) === "bottom",
|
|
19157
19323
|
icon: "o-spreadsheet-Icon.ALIGN_BOTTOM",
|
|
19158
19324
|
};
|
|
19159
|
-
const
|
|
19325
|
+
const formatWrappingIcon = {
|
|
19160
19326
|
name: _lt("Wrapping"),
|
|
19161
19327
|
icon: "o-spreadsheet-Icon.WRAPPING_OVERFLOW",
|
|
19162
19328
|
};
|
|
19329
|
+
const formatWrapping = {
|
|
19330
|
+
name: _lt("Wrapping"),
|
|
19331
|
+
icon: (env) => getWrapModeIcon(env),
|
|
19332
|
+
};
|
|
19163
19333
|
const formatWrappingOverflow = {
|
|
19164
19334
|
name: _lt("Overflow"),
|
|
19165
19335
|
execute: (env) => setStyle(env, { wrapping: "overflow" }),
|
|
19166
|
-
isActive: (env) => (env
|
|
19336
|
+
isActive: (env) => getWrappingMode(env) === "overflow",
|
|
19167
19337
|
icon: "o-spreadsheet-Icon.WRAPPING_OVERFLOW",
|
|
19168
19338
|
};
|
|
19169
19339
|
const formatWrappingWrap = {
|
|
19170
19340
|
name: _lt("Wrap"),
|
|
19171
19341
|
execute: (env) => setStyle(env, { wrapping: "wrap" }),
|
|
19172
|
-
isActive: (env) => env
|
|
19342
|
+
isActive: (env) => getWrappingMode(env) === "wrap",
|
|
19173
19343
|
icon: "o-spreadsheet-Icon.WRAPPING_WRAP",
|
|
19174
19344
|
};
|
|
19175
19345
|
const formatWrappingClip = {
|
|
19176
19346
|
name: _lt("Clip"),
|
|
19177
19347
|
execute: (env) => setStyle(env, { wrapping: "clip" }),
|
|
19178
|
-
isActive: (env) => env
|
|
19348
|
+
isActive: (env) => getWrappingMode(env) === "clip",
|
|
19179
19349
|
icon: "o-spreadsheet-Icon.WRAPPING_CLIP",
|
|
19180
19350
|
};
|
|
19181
19351
|
const textColor = {
|
|
@@ -19191,14 +19361,6 @@ const formatCF = {
|
|
|
19191
19361
|
execute: OPEN_CF_SIDEPANEL_ACTION,
|
|
19192
19362
|
icon: "o-spreadsheet-Icon.CONDITIONAL_FORMAT",
|
|
19193
19363
|
};
|
|
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
19364
|
const clearFormat = {
|
|
19203
19365
|
name: _lt("Clear formatting"),
|
|
19204
19366
|
description: "Ctrl+<",
|
|
@@ -19238,6 +19400,53 @@ function getHorizontalAlign(env) {
|
|
|
19238
19400
|
}
|
|
19239
19401
|
const cell = env.model.getters.getActiveCell();
|
|
19240
19402
|
return cell.defaultAlign;
|
|
19403
|
+
}
|
|
19404
|
+
function getVerticalAlign(env) {
|
|
19405
|
+
const style = env.model.getters.getCurrentStyle();
|
|
19406
|
+
if (style.verticalAlign) {
|
|
19407
|
+
return style.verticalAlign;
|
|
19408
|
+
}
|
|
19409
|
+
return DEFAULT_VERTICAL_ALIGN;
|
|
19410
|
+
}
|
|
19411
|
+
function getWrappingMode(env) {
|
|
19412
|
+
const style = env.model.getters.getCurrentStyle();
|
|
19413
|
+
if (style.wrapping) {
|
|
19414
|
+
return style.wrapping;
|
|
19415
|
+
}
|
|
19416
|
+
return DEFAULT_WRAPPING_MODE;
|
|
19417
|
+
}
|
|
19418
|
+
function getHorizontalAlignmentIcon(env) {
|
|
19419
|
+
const horizontalAlign = getHorizontalAlign(env);
|
|
19420
|
+
switch (horizontalAlign) {
|
|
19421
|
+
case "right":
|
|
19422
|
+
return "o-spreadsheet-Icon.ALIGN_RIGHT";
|
|
19423
|
+
case "center":
|
|
19424
|
+
return "o-spreadsheet-Icon.ALIGN_CENTER";
|
|
19425
|
+
default:
|
|
19426
|
+
return "o-spreadsheet-Icon.ALIGN_LEFT";
|
|
19427
|
+
}
|
|
19428
|
+
}
|
|
19429
|
+
function getVerticalAlignmentIcon(env) {
|
|
19430
|
+
const verticalAlign = getVerticalAlign(env);
|
|
19431
|
+
switch (verticalAlign) {
|
|
19432
|
+
case "top":
|
|
19433
|
+
return "o-spreadsheet-Icon.ALIGN_TOP";
|
|
19434
|
+
case "middle":
|
|
19435
|
+
return "o-spreadsheet-Icon.ALIGN_MIDDLE";
|
|
19436
|
+
default:
|
|
19437
|
+
return "o-spreadsheet-Icon.ALIGN_BOTTOM";
|
|
19438
|
+
}
|
|
19439
|
+
}
|
|
19440
|
+
function getWrapModeIcon(env) {
|
|
19441
|
+
const wrapMode = getWrappingMode(env);
|
|
19442
|
+
switch (wrapMode) {
|
|
19443
|
+
case "wrap":
|
|
19444
|
+
return "o-spreadsheet-Icon.WRAPPING_WRAP";
|
|
19445
|
+
case "clip":
|
|
19446
|
+
return "o-spreadsheet-Icon.WRAPPING_CLIP";
|
|
19447
|
+
default:
|
|
19448
|
+
return "o-spreadsheet-Icon.WRAPPING_OVERFLOW";
|
|
19449
|
+
}
|
|
19241
19450
|
}
|
|
19242
19451
|
|
|
19243
19452
|
var ACTION_FORMAT = /*#__PURE__*/Object.freeze({
|
|
@@ -19269,6 +19478,7 @@ var ACTION_FORMAT = /*#__PURE__*/Object.freeze({
|
|
|
19269
19478
|
formatAlignmentTop: formatAlignmentTop,
|
|
19270
19479
|
formatAlignmentMiddle: formatAlignmentMiddle,
|
|
19271
19480
|
formatAlignmentBottom: formatAlignmentBottom,
|
|
19481
|
+
formatWrappingIcon: formatWrappingIcon,
|
|
19272
19482
|
formatWrapping: formatWrapping,
|
|
19273
19483
|
formatWrappingOverflow: formatWrappingOverflow,
|
|
19274
19484
|
formatWrappingWrap: formatWrappingWrap,
|
|
@@ -19276,7 +19486,6 @@ var ACTION_FORMAT = /*#__PURE__*/Object.freeze({
|
|
|
19276
19486
|
textColor: textColor,
|
|
19277
19487
|
fillColor: fillColor,
|
|
19278
19488
|
formatCF: formatCF,
|
|
19279
|
-
paintFormat: paintFormat,
|
|
19280
19489
|
clearFormat: clearFormat
|
|
19281
19490
|
});
|
|
19282
19491
|
|
|
@@ -20039,7 +20248,7 @@ topbarMenuRegistry
|
|
|
20039
20248
|
separator: true,
|
|
20040
20249
|
})
|
|
20041
20250
|
.addChild("format_wrapping", ["format"], {
|
|
20042
|
-
...
|
|
20251
|
+
...formatWrappingIcon,
|
|
20043
20252
|
sequence: 80,
|
|
20044
20253
|
separator: true,
|
|
20045
20254
|
})
|
|
@@ -22329,17 +22538,45 @@ class CustomCurrencyPanel extends Component {
|
|
|
22329
22538
|
}
|
|
22330
22539
|
get formatProposals() {
|
|
22331
22540
|
const currency = this.availableCurrencies[this.state.selectedCurrencyIndex];
|
|
22332
|
-
const
|
|
22333
|
-
const
|
|
22334
|
-
const secondPosition = currency.position === "before" ? "after" : "before";
|
|
22541
|
+
const position = currency.position;
|
|
22542
|
+
const opposite = currency.position === "before" ? "after" : "before";
|
|
22335
22543
|
const symbol = this.state.currencySymbol.trim() ? this.state.currencySymbol : "";
|
|
22336
22544
|
const code = this.state.currencyCode.trim() ? this.state.currencyCode : "";
|
|
22337
|
-
|
|
22338
|
-
|
|
22339
|
-
|
|
22340
|
-
|
|
22341
|
-
|
|
22342
|
-
|
|
22545
|
+
const decimalPlaces = currency.decimalPlaces;
|
|
22546
|
+
if (!symbol && !code) {
|
|
22547
|
+
return [];
|
|
22548
|
+
}
|
|
22549
|
+
const simple = symbol ? createCurrencyFormat({ symbol, position, decimalPlaces }) : "";
|
|
22550
|
+
const rounded = simple ? roundFormat(simple) : "";
|
|
22551
|
+
const simpleWithCode = createCurrencyFormat({ symbol, position, decimalPlaces, code });
|
|
22552
|
+
const roundedWithCode = roundFormat(simpleWithCode);
|
|
22553
|
+
const simpleOpposite = symbol
|
|
22554
|
+
? createCurrencyFormat({ symbol, position: opposite, decimalPlaces })
|
|
22555
|
+
: "";
|
|
22556
|
+
const roundedOpposite = simpleOpposite ? roundFormat(simpleOpposite) : "";
|
|
22557
|
+
const simpleOppositeWithCode = createCurrencyFormat({
|
|
22558
|
+
symbol,
|
|
22559
|
+
position: opposite,
|
|
22560
|
+
decimalPlaces,
|
|
22561
|
+
code,
|
|
22562
|
+
});
|
|
22563
|
+
const roundedOppositeWithCode = roundFormat(simpleOppositeWithCode);
|
|
22564
|
+
const formats = new Set([
|
|
22565
|
+
rounded,
|
|
22566
|
+
simple,
|
|
22567
|
+
roundedWithCode,
|
|
22568
|
+
simpleWithCode,
|
|
22569
|
+
roundedOpposite,
|
|
22570
|
+
simpleOpposite,
|
|
22571
|
+
roundedOppositeWithCode,
|
|
22572
|
+
simpleOppositeWithCode,
|
|
22573
|
+
]);
|
|
22574
|
+
return [...formats]
|
|
22575
|
+
.filter((format) => format !== "")
|
|
22576
|
+
.map((format) => ({
|
|
22577
|
+
format,
|
|
22578
|
+
example: formatValue(1000.0, { format, locale: this.env.model.getters.getLocale() }),
|
|
22579
|
+
}));
|
|
22343
22580
|
}
|
|
22344
22581
|
get isSameFormat() {
|
|
22345
22582
|
const selectedFormat = this.formatProposals[this.state.selectedFormatIndex];
|
|
@@ -22396,41 +22633,6 @@ class CustomCurrencyPanel extends Component {
|
|
|
22396
22633
|
initAvailableCurrencies() {
|
|
22397
22634
|
this.state.selectedCurrencyIndex = 0;
|
|
22398
22635
|
}
|
|
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
22636
|
getCommonFormat() {
|
|
22435
22637
|
const selectedZones = this.env.model.getters.getSelectedZones();
|
|
22436
22638
|
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
@@ -22487,6 +22689,7 @@ class FindAndReplacePanel extends Component {
|
|
|
22487
22689
|
state = useState(this.initialState());
|
|
22488
22690
|
debounceTimeoutId;
|
|
22489
22691
|
showFormulaState = false;
|
|
22692
|
+
debouncedUpdateSearch;
|
|
22490
22693
|
findAndReplaceRef = useRef("findAndReplace");
|
|
22491
22694
|
get hasSearchResult() {
|
|
22492
22695
|
return this.env.model.getters.getCurrentSelectedMatchIndex() !== null;
|
|
@@ -22496,11 +22699,16 @@ class FindAndReplacePanel extends Component {
|
|
|
22496
22699
|
}
|
|
22497
22700
|
setup() {
|
|
22498
22701
|
this.showFormulaState = this.env.model.getters.shouldShowFormulas();
|
|
22702
|
+
this.debouncedUpdateSearch = debounce(this.updateSearch.bind(this), 200);
|
|
22499
22703
|
onMounted(() => this.focusInput());
|
|
22500
22704
|
onWillUnmount(() => {
|
|
22501
22705
|
this.env.model.dispatch("CLEAR_SEARCH");
|
|
22502
22706
|
this.env.model.dispatch("SET_FORMULA_VISIBILITY", { show: this.showFormulaState });
|
|
22503
22707
|
});
|
|
22708
|
+
useEffect(() => {
|
|
22709
|
+
this.state.searchOptions.searchFormulas = this.env.model.getters.shouldShowFormulas();
|
|
22710
|
+
this.searchFormulas();
|
|
22711
|
+
}, () => [this.env.model.getters.shouldShowFormulas()]);
|
|
22504
22712
|
}
|
|
22505
22713
|
onInput(ev) {
|
|
22506
22714
|
this.state.toSearch = ev.target.value;
|
|
@@ -22520,10 +22728,6 @@ class FindAndReplacePanel extends Component {
|
|
|
22520
22728
|
this.replace();
|
|
22521
22729
|
}
|
|
22522
22730
|
}
|
|
22523
|
-
onFocusSidePanel() {
|
|
22524
|
-
this.state.searchOptions.searchFormulas = this.env.model.getters.shouldShowFormulas();
|
|
22525
|
-
this.env.model.dispatch("REFRESH_SEARCH");
|
|
22526
|
-
}
|
|
22527
22731
|
searchFormulas() {
|
|
22528
22732
|
this.env.model.dispatch("SET_FORMULA_VISIBILITY", {
|
|
22529
22733
|
show: this.state.searchOptions.searchFormulas,
|
|
@@ -22542,13 +22746,6 @@ class FindAndReplacePanel extends Component {
|
|
|
22542
22746
|
searchOptions: this.state.searchOptions,
|
|
22543
22747
|
});
|
|
22544
22748
|
}
|
|
22545
|
-
debouncedUpdateSearch() {
|
|
22546
|
-
clearTimeout(this.debounceTimeoutId);
|
|
22547
|
-
this.debounceTimeoutId = setTimeout(() => {
|
|
22548
|
-
this.updateSearch();
|
|
22549
|
-
this.debounceTimeoutId = undefined;
|
|
22550
|
-
}, 400);
|
|
22551
|
-
}
|
|
22552
22749
|
replace() {
|
|
22553
22750
|
this.env.model.dispatch("REPLACE_SEARCH", {
|
|
22554
22751
|
replaceWith: this.state.replaceWith,
|
|
@@ -23233,7 +23430,7 @@ class ContentEditableHelper {
|
|
|
23233
23430
|
selection.removeAllRanges();
|
|
23234
23431
|
selection.addRange(range);
|
|
23235
23432
|
}
|
|
23236
|
-
if (start
|
|
23433
|
+
if (start === end && start === 0) {
|
|
23237
23434
|
range.setStart(this.el, 0);
|
|
23238
23435
|
range.setEnd(this.el, 0);
|
|
23239
23436
|
}
|
|
@@ -23486,7 +23683,7 @@ class ContentEditableHelper {
|
|
|
23486
23683
|
}, 0);
|
|
23487
23684
|
}
|
|
23488
23685
|
}
|
|
23489
|
-
if (nodeToFind.nodeName === "P" && !isFirstParagraph && nodeToFind.textContent
|
|
23686
|
+
if (nodeToFind.nodeName === "P" && !isFirstParagraph && nodeToFind.textContent === "") {
|
|
23490
23687
|
usedCharacters++;
|
|
23491
23688
|
}
|
|
23492
23689
|
return usedCharacters;
|
|
@@ -25033,6 +25230,14 @@ function useInterval(callback, delay) {
|
|
|
25033
25230
|
};
|
|
25034
25231
|
}
|
|
25035
25232
|
|
|
25233
|
+
const CURSOR_SVG = /*xml*/ `
|
|
25234
|
+
<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>
|
|
25235
|
+
`;
|
|
25236
|
+
css /* scss */ `
|
|
25237
|
+
.o-paint-format-cursor {
|
|
25238
|
+
cursor: url("data:image/svg+xml,${encodeURIComponent(CURSOR_SVG)}"), auto;
|
|
25239
|
+
}
|
|
25240
|
+
`;
|
|
25036
25241
|
function useCellHovered(env, gridRef, callback) {
|
|
25037
25242
|
let hoveredPosition = {
|
|
25038
25243
|
col: undefined,
|
|
@@ -25156,6 +25361,12 @@ class GridOverlay extends Component {
|
|
|
25156
25361
|
}
|
|
25157
25362
|
return this.gridOverlay.el;
|
|
25158
25363
|
}
|
|
25364
|
+
get style() {
|
|
25365
|
+
return this.props.gridOverlayDimensions;
|
|
25366
|
+
}
|
|
25367
|
+
get isPaintingFormat() {
|
|
25368
|
+
return this.env.model.getters.isPaintingFormat();
|
|
25369
|
+
}
|
|
25159
25370
|
onMouseDown(ev) {
|
|
25160
25371
|
if (ev.button > 0) {
|
|
25161
25372
|
// not main button, probably a context menu
|
|
@@ -26333,6 +26544,9 @@ class Grid extends Component {
|
|
|
26333
26544
|
else if (this.menuState.isOpen) {
|
|
26334
26545
|
this.closeMenu();
|
|
26335
26546
|
}
|
|
26547
|
+
else if (this.env.model.getters.isPaintingFormat()) {
|
|
26548
|
+
this.env.model.dispatch("CANCEL_PAINT_FORMAT");
|
|
26549
|
+
}
|
|
26336
26550
|
else {
|
|
26337
26551
|
this.env.model.dispatch("CLEAN_CLIPBOARD_HIGHLIGHT");
|
|
26338
26552
|
}
|
|
@@ -27535,8 +27749,8 @@ function convertXlsxFormat(numFmtId, formats, warningManager) {
|
|
|
27535
27749
|
throw new Error("Multiple escaped blocks in format");
|
|
27536
27750
|
}
|
|
27537
27751
|
convertedFormat = convertedFormat.replace(/"(.*)"/g, "[$$$1]"); // replace '"..."' by '[$...]'
|
|
27538
|
-
convertedFormat = convertedFormat.replace(/_.{1}/g, ""); // _
|
|
27539
|
-
convertedFormat = convertedFormat.replace(/\*.{1}/g, ""); // *
|
|
27752
|
+
convertedFormat = convertedFormat.replace(/_.{1}/g, ""); // _ === ignore width of next char for align purposes. Not supported ATM
|
|
27753
|
+
convertedFormat = convertedFormat.replace(/\*.{1}/g, ""); // * === repeat next character enough to fill the line. Not supported ATM
|
|
27540
27754
|
convertedFormat = convertedFormat.replace(/\\ /g, " "); // unescape spaces
|
|
27541
27755
|
convertedFormat = convertedFormat.replace(/\\./g, (match) => match[1]); // unescape other characters
|
|
27542
27756
|
if (isXlsxDateFormat(convertedFormat)) {
|
|
@@ -28828,29 +29042,26 @@ function escapeXml(strings, ...expressions) {
|
|
|
28828
29042
|
return new XMLString(concat(str));
|
|
28829
29043
|
}
|
|
28830
29044
|
/**
|
|
28831
|
-
* Removes the namespace of all the xml tags in the string.
|
|
29045
|
+
* Removes the escaped namespace of all the xml tags in the string.
|
|
28832
29046
|
*
|
|
28833
|
-
* Eg. : "
|
|
29047
|
+
* Eg. : "NAMESPACEnsNAMESPACEtest a" => "test a"
|
|
28834
29048
|
*/
|
|
28835
|
-
function
|
|
28836
|
-
return
|
|
29049
|
+
function removeTagEscapedNamespaces(tag) {
|
|
29050
|
+
return tag.replace(/NAMESPACE.*NAMESPACE(.*)/, "$1");
|
|
28837
29051
|
}
|
|
28838
29052
|
/**
|
|
28839
|
-
*
|
|
29053
|
+
* Encase the namespaces in the element's tags with NAMESPACE string
|
|
28840
29054
|
*
|
|
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.
|
|
29055
|
+
* e.g. <x:foo> becomes <NAMESPACExNAMESPACEFoo>
|
|
28848
29056
|
*
|
|
28849
|
-
*
|
|
29057
|
+
* That's useful because namespaces aren't supported by the HTML specification, so it's arbitrary whether a HTML parser/querySelector
|
|
29058
|
+
* implementation will support namespaces in the tags or not.
|
|
28850
29059
|
*/
|
|
28851
|
-
function
|
|
28852
|
-
|
|
28853
|
-
|
|
29060
|
+
function escapeTagNamespaces(str) {
|
|
29061
|
+
return str.replaceAll(/(<\/?)([a-zA-Z0-9]+):([a-zA-Z0-9]+)/g, "$1" + "NAMESPACE" + "$2" + "NAMESPACE" + "$3");
|
|
29062
|
+
}
|
|
29063
|
+
function escapeQueryNameSpaces(query) {
|
|
29064
|
+
return query.replaceAll(/([a-zA-Z0-9]+):([a-zA-Z0-9]+)/g, "NAMESPACE" + "$1" + "NAMESPACE" + "$2");
|
|
28854
29065
|
}
|
|
28855
29066
|
|
|
28856
29067
|
class AttributeValue {
|
|
@@ -28880,14 +29091,20 @@ class XlsxBaseExtractor {
|
|
|
28880
29091
|
// The xml file we are currently parsing. We should have one Extractor class by XLSXImportFile, but
|
|
28881
29092
|
// the XLSXImportFile contains both the main .xml file, and the .rels file
|
|
28882
29093
|
currentFile = undefined;
|
|
28883
|
-
|
|
28884
|
-
|
|
29094
|
+
/**
|
|
29095
|
+
* /!\ Important : There should be no namespaces in the tags of the XML files.
|
|
29096
|
+
*
|
|
29097
|
+
* This class use native querySelector and querySelectorAll, that's used for HTML (not XML). These aren't supposed to
|
|
29098
|
+
* handled namespaces, as they are not supported by the HTML specification. Some implementations (most browsers) do
|
|
29099
|
+
* actually support namespaces, but some don't (e.g. jsdom).
|
|
29100
|
+
*
|
|
29101
|
+
* The namespace should be escaped as with NAMESPACE string (eg. <t:foo> => <NAMESPACEtNAMESPACEfoo>).
|
|
29102
|
+
*/
|
|
28885
29103
|
constructor(rootFile, xlsxStructure, warningManager) {
|
|
28886
29104
|
this.rootFile = rootFile;
|
|
28887
29105
|
this.currentFile = rootFile.file.fileName;
|
|
28888
29106
|
this.xlsxFileStructure = xlsxStructure;
|
|
28889
29107
|
this.warningManager = warningManager;
|
|
28890
|
-
this.areNamespaceIgnored = areNamespaceIgnoredByQuerySelector();
|
|
28891
29108
|
this.relationships = {};
|
|
28892
29109
|
if (rootFile.rels) {
|
|
28893
29110
|
this.extractRelationships(rootFile.rels).map((rel) => {
|
|
@@ -29113,29 +29330,13 @@ class XlsxBaseExtractor {
|
|
|
29113
29330
|
throw new Error("Cannot find target file");
|
|
29114
29331
|
return f;
|
|
29115
29332
|
}
|
|
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
29333
|
querySelector(element, query) {
|
|
29125
|
-
|
|
29126
|
-
return element.querySelector(
|
|
29334
|
+
const escapedQuery = escapeQueryNameSpaces(query);
|
|
29335
|
+
return element.querySelector(escapedQuery);
|
|
29127
29336
|
}
|
|
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
29337
|
querySelectorAll(element, query) {
|
|
29137
|
-
|
|
29138
|
-
return element.querySelectorAll(
|
|
29338
|
+
const escapedQuery = escapeQueryNameSpaces(query);
|
|
29339
|
+
return element.querySelectorAll(escapedQuery);
|
|
29139
29340
|
}
|
|
29140
29341
|
/**
|
|
29141
29342
|
* Get a color from its id in the Theme's colorScheme.
|
|
@@ -29375,7 +29576,7 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
|
|
|
29375
29576
|
throw new Error("Missing plot area in the chart definition.");
|
|
29376
29577
|
}
|
|
29377
29578
|
for (let child of plotAreaElement.children) {
|
|
29378
|
-
const tag =
|
|
29579
|
+
const tag = removeTagEscapedNamespaces(child.tagName);
|
|
29379
29580
|
if (XLSX_CHART_TYPES.some((chartType) => chartType === tag)) {
|
|
29380
29581
|
return tag;
|
|
29381
29582
|
}
|
|
@@ -29387,7 +29588,7 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
|
|
|
29387
29588
|
class XlsxFigureExtractor extends XlsxBaseExtractor {
|
|
29388
29589
|
extractFigures() {
|
|
29389
29590
|
return this.mapOnElements({ parent: this.rootFile.file.xml, query: "xdr:wsDr", children: true }, (figureElement) => {
|
|
29390
|
-
const anchorType =
|
|
29591
|
+
const anchorType = removeTagEscapedNamespaces(figureElement.tagName);
|
|
29391
29592
|
if (anchorType !== "twoCellAnchor") {
|
|
29392
29593
|
throw new Error("Only twoCellAnchor are supported for xlsx drawings.");
|
|
29393
29594
|
}
|
|
@@ -30021,7 +30222,8 @@ class XlsxReader {
|
|
|
30021
30222
|
for (let key of Object.keys(files)) {
|
|
30022
30223
|
// Random files can be in xlsx (like a bin file for printer settings)
|
|
30023
30224
|
if (key.endsWith(".xml") || key.endsWith(".rels")) {
|
|
30024
|
-
|
|
30225
|
+
const contentString = escapeTagNamespaces(files[key]);
|
|
30226
|
+
this.xmls[key] = parseXML(new XMLString(contentString));
|
|
30025
30227
|
}
|
|
30026
30228
|
else if (key.includes("media/image")) {
|
|
30027
30229
|
this.images.push({
|
|
@@ -31088,7 +31290,7 @@ class BordersPlugin extends CorePlugin {
|
|
|
31088
31290
|
}
|
|
31089
31291
|
/**
|
|
31090
31292
|
* Set the borders of a cell.
|
|
31091
|
-
* It overrides the current border if override
|
|
31293
|
+
* It overrides the current border if override === true.
|
|
31092
31294
|
*/
|
|
31093
31295
|
setBorder(sheetId, col, row, border, override = true) {
|
|
31094
31296
|
if (override || !this.borders?.[sheetId]?.[col]?.[row]?.vertical) {
|
|
@@ -32358,7 +32560,9 @@ class FigurePlugin extends CorePlugin {
|
|
|
32358
32560
|
const numHeader = this.getters.getNumberRows(sheetId);
|
|
32359
32561
|
let gridHeight = 0;
|
|
32360
32562
|
for (let i = 0; i < numHeader; i++) {
|
|
32361
|
-
|
|
32563
|
+
// TODO : since the row size is an UI value now, this doesn't work anymore. Using the default cell height is
|
|
32564
|
+
// a temporary solution at best, but is broken.
|
|
32565
|
+
gridHeight += this.getters.getUserRowSize(sheetId, i) || DEFAULT_CELL_HEIGHT;
|
|
32362
32566
|
}
|
|
32363
32567
|
const figures = this.getters.getFigures(sheetId);
|
|
32364
32568
|
for (const figure of figures) {
|
|
@@ -32784,33 +32988,15 @@ class FiltersPlugin extends CorePlugin {
|
|
|
32784
32988
|
}
|
|
32785
32989
|
|
|
32786
32990
|
class HeaderSizePlugin extends CorePlugin {
|
|
32787
|
-
static getters = ["
|
|
32991
|
+
static getters = ["getUserRowSize", "getColSize"];
|
|
32788
32992
|
sizes = {};
|
|
32789
32993
|
handle(cmd) {
|
|
32790
32994
|
switch (cmd.type) {
|
|
32791
32995
|
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);
|
|
32996
|
+
this.history.update("sizes", cmd.sheetId, { COL: [], ROW: [] });
|
|
32804
32997
|
break;
|
|
32805
32998
|
}
|
|
32806
32999
|
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
33000
|
this.history.update("sizes", cmd.sheetIdTo, deepCopy(this.sizes[cmd.sheetId]));
|
|
32815
33001
|
break;
|
|
32816
33002
|
case "DELETE_SHEET":
|
|
@@ -32819,21 +33005,8 @@ class HeaderSizePlugin extends CorePlugin {
|
|
|
32819
33005
|
this.history.update("sizes", sizes);
|
|
32820
33006
|
break;
|
|
32821
33007
|
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
|
-
});
|
|
33008
|
+
const arr = this.sizes[cmd.sheetId][cmd.dimension];
|
|
33009
|
+
const sizes = removeIndexesFromArray(arr, cmd.elements);
|
|
32837
33010
|
this.history.update("sizes", cmd.sheetId, cmd.dimension, sizes);
|
|
32838
33011
|
break;
|
|
32839
33012
|
}
|
|
@@ -32842,51 +33015,18 @@ class HeaderSizePlugin extends CorePlugin {
|
|
|
32842
33015
|
const addIndex = getAddHeaderStartIndex(cmd.position, cmd.base);
|
|
32843
33016
|
const baseSize = sizes[cmd.base];
|
|
32844
33017
|
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
33018
|
this.history.update("sizes", cmd.sheetId, cmd.dimension, sizes);
|
|
32856
33019
|
break;
|
|
32857
33020
|
}
|
|
32858
33021
|
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
|
-
});
|
|
33022
|
+
if (cmd.dimension === "ROW") {
|
|
33023
|
+
for (const el of cmd.elements) {
|
|
33024
|
+
this.history.update("sizes", cmd.sheetId, cmd.dimension, el, cmd.size || undefined);
|
|
32873
33025
|
}
|
|
32874
33026
|
}
|
|
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
|
-
}
|
|
33027
|
+
else {
|
|
33028
|
+
for (const el of cmd.elements) {
|
|
33029
|
+
this.history.update("sizes", cmd.sheetId, cmd.dimension, el, cmd.size || undefined);
|
|
32890
33030
|
}
|
|
32891
33031
|
}
|
|
32892
33032
|
break;
|
|
@@ -32894,94 +33034,29 @@ class HeaderSizePlugin extends CorePlugin {
|
|
|
32894
33034
|
return;
|
|
32895
33035
|
}
|
|
32896
33036
|
getColSize(sheetId, index) {
|
|
32897
|
-
return this.
|
|
32898
|
-
}
|
|
32899
|
-
getRowSize(sheetId, index) {
|
|
32900
|
-
return this.getHeaderSize(sheetId, "ROW", index);
|
|
32901
|
-
}
|
|
32902
|
-
getHeaderSize(sheetId, dimension, index) {
|
|
32903
|
-
return Math.round(this.sizes[sheetId]?.[dimension][index]?.manualSize ||
|
|
32904
|
-
this.sizes[sheetId]?.[dimension][index]?.computedSize() ||
|
|
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;
|
|
33037
|
+
return Math.round(this.sizes[sheetId]?.["COL"][index] || DEFAULT_CELL_WIDTH);
|
|
32921
33038
|
}
|
|
32922
|
-
|
|
32923
|
-
|
|
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;
|
|
33039
|
+
getUserRowSize(sheetId, index) {
|
|
33040
|
+
const rowSize = this.sizes[sheetId]?.["ROW"][index];
|
|
33041
|
+
return rowSize ? Math.round(rowSize) : undefined;
|
|
32960
33042
|
}
|
|
32961
33043
|
import(data) {
|
|
32962
33044
|
for (let sheet of data.sheets) {
|
|
32963
|
-
const
|
|
33045
|
+
const sizes = {
|
|
33046
|
+
COL: Array(sheet.colNumber).fill(undefined),
|
|
33047
|
+
ROW: Array(sheet.rowNumber).fill(undefined),
|
|
33048
|
+
};
|
|
32964
33049
|
for (let [rowIndex, row] of Object.entries(sheet.rows)) {
|
|
32965
33050
|
if (row.size) {
|
|
32966
|
-
|
|
33051
|
+
sizes["ROW"][rowIndex] = row.size;
|
|
32967
33052
|
}
|
|
32968
33053
|
}
|
|
32969
33054
|
for (let [colIndex, col] of Object.entries(sheet.cols)) {
|
|
32970
33055
|
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
|
-
};
|
|
33056
|
+
sizes["COL"][colIndex] = col.size;
|
|
33057
|
+
}
|
|
33058
|
+
}
|
|
33059
|
+
this.sizes[sheet.id] = sizes;
|
|
32985
33060
|
}
|
|
32986
33061
|
return;
|
|
32987
33062
|
}
|
|
@@ -33002,9 +33077,12 @@ class HeaderSizePlugin extends CorePlugin {
|
|
|
33002
33077
|
if (sheet.rows === undefined) {
|
|
33003
33078
|
sheet.rows = {};
|
|
33004
33079
|
}
|
|
33005
|
-
for (
|
|
33006
|
-
if (exportDefaults || this.sizes[sheet.id]["ROW"][row]
|
|
33007
|
-
sheet.rows[row] = {
|
|
33080
|
+
for (const row of range(0, this.getters.getNumberRows(sheet.id))) {
|
|
33081
|
+
if (exportDefaults || this.sizes[sheet.id]["ROW"][row]) {
|
|
33082
|
+
sheet.rows[row] = {
|
|
33083
|
+
...sheet.rows[row],
|
|
33084
|
+
size: this.getUserRowSize(sheet.id, row) ?? DEFAULT_CELL_HEIGHT,
|
|
33085
|
+
};
|
|
33008
33086
|
}
|
|
33009
33087
|
}
|
|
33010
33088
|
// Export col sizes
|
|
@@ -33012,7 +33090,7 @@ class HeaderSizePlugin extends CorePlugin {
|
|
|
33012
33090
|
sheet.cols = {};
|
|
33013
33091
|
}
|
|
33014
33092
|
for (let col of range(0, this.getters.getNumberCols(sheet.id))) {
|
|
33015
|
-
if (exportDefaults || this.sizes[sheet.id]["COL"][col]
|
|
33093
|
+
if (exportDefaults || this.sizes[sheet.id]["COL"][col]) {
|
|
33016
33094
|
sheet.cols[col] = { ...sheet.cols[col], size: this.getColSize(sheet.id, col) };
|
|
33017
33095
|
}
|
|
33018
33096
|
}
|
|
@@ -36568,7 +36646,7 @@ class EvaluationConditionalFormatPlugin extends UIPlugin {
|
|
|
36568
36646
|
case "ContainsText":
|
|
36569
36647
|
return cell.value.toString().indexOf(values[0].toString()) > -1;
|
|
36570
36648
|
case "NotContains":
|
|
36571
|
-
return !cell.value || cell.value.toString().indexOf(values[0].toString())
|
|
36649
|
+
return !cell.value || cell.value.toString().indexOf(values[0].toString()) === -1;
|
|
36572
36650
|
case "GreaterThan":
|
|
36573
36651
|
return cell.value > values[0];
|
|
36574
36652
|
case "GreaterThanOrEqual":
|
|
@@ -36595,6 +36673,156 @@ class EvaluationConditionalFormatPlugin extends UIPlugin {
|
|
|
36595
36673
|
};
|
|
36596
36674
|
}
|
|
36597
36675
|
|
|
36676
|
+
class UIRowSizePlugin extends UIPlugin {
|
|
36677
|
+
static getters = ["getRowSize"];
|
|
36678
|
+
tallestCellInRow = {};
|
|
36679
|
+
ctx = document.createElement("canvas").getContext("2d");
|
|
36680
|
+
handle(cmd) {
|
|
36681
|
+
switch (cmd.type) {
|
|
36682
|
+
case "START":
|
|
36683
|
+
for (const sheetId of this.getters.getSheetIds()) {
|
|
36684
|
+
this.initializeSheet(sheetId);
|
|
36685
|
+
}
|
|
36686
|
+
break;
|
|
36687
|
+
case "CREATE_SHEET": {
|
|
36688
|
+
this.initializeSheet(cmd.sheetId);
|
|
36689
|
+
break;
|
|
36690
|
+
}
|
|
36691
|
+
case "DUPLICATE_SHEET": {
|
|
36692
|
+
const tallestCells = deepCopy(this.tallestCellInRow[cmd.sheetId]);
|
|
36693
|
+
this.history.update("tallestCellInRow", cmd.sheetIdTo, tallestCells);
|
|
36694
|
+
break;
|
|
36695
|
+
}
|
|
36696
|
+
case "DELETE_SHEET":
|
|
36697
|
+
const tallestCells = { ...this.tallestCellInRow };
|
|
36698
|
+
delete tallestCells[cmd.sheetId];
|
|
36699
|
+
this.history.update("tallestCellInRow", tallestCells);
|
|
36700
|
+
break;
|
|
36701
|
+
case "REMOVE_COLUMNS_ROWS": {
|
|
36702
|
+
if (cmd.dimension === "COL") {
|
|
36703
|
+
return;
|
|
36704
|
+
}
|
|
36705
|
+
const tallestCells = removeIndexesFromArray(this.tallestCellInRow[cmd.sheetId], cmd.elements);
|
|
36706
|
+
this.history.update("tallestCellInRow", cmd.sheetId, tallestCells);
|
|
36707
|
+
break;
|
|
36708
|
+
}
|
|
36709
|
+
case "ADD_COLUMNS_ROWS": {
|
|
36710
|
+
if (cmd.dimension === "COL") {
|
|
36711
|
+
return;
|
|
36712
|
+
}
|
|
36713
|
+
const addIndex = getAddHeaderStartIndex(cmd.position, cmd.base);
|
|
36714
|
+
const newCells = Array(cmd.quantity).fill(undefined);
|
|
36715
|
+
const newTallestCells = insertItemsAtIndex(this.tallestCellInRow[cmd.sheetId], newCells, addIndex);
|
|
36716
|
+
this.history.update("tallestCellInRow", cmd.sheetId, newTallestCells);
|
|
36717
|
+
break;
|
|
36718
|
+
}
|
|
36719
|
+
case "RESIZE_COLUMNS_ROWS":
|
|
36720
|
+
{
|
|
36721
|
+
const sheetId = cmd.sheetId;
|
|
36722
|
+
if (cmd.dimension === "ROW") {
|
|
36723
|
+
for (const row of cmd.elements) {
|
|
36724
|
+
const tallestCell = this.getRowTallestCell(sheetId, row);
|
|
36725
|
+
this.history.update("tallestCellInRow", sheetId, row, tallestCell);
|
|
36726
|
+
}
|
|
36727
|
+
}
|
|
36728
|
+
else {
|
|
36729
|
+
// Recompute row heights on col size change, they might have changed because of wrapped text
|
|
36730
|
+
for (const row of range(0, this.getters.getNumberRows(sheetId))) {
|
|
36731
|
+
for (const col of cmd.elements) {
|
|
36732
|
+
this.updateRowSizeForCellChange(sheetId, row, col);
|
|
36733
|
+
}
|
|
36734
|
+
}
|
|
36735
|
+
}
|
|
36736
|
+
}
|
|
36737
|
+
break;
|
|
36738
|
+
case "UPDATE_CELL":
|
|
36739
|
+
this.updateRowSizeForCellChange(cmd.sheetId, cmd.row, cmd.col);
|
|
36740
|
+
break;
|
|
36741
|
+
case "ADD_MERGE":
|
|
36742
|
+
case "REMOVE_MERGE":
|
|
36743
|
+
for (const target of cmd.target) {
|
|
36744
|
+
for (const position of positions(target)) {
|
|
36745
|
+
this.updateRowSizeForCellChange(cmd.sheetId, position.row, position.col);
|
|
36746
|
+
}
|
|
36747
|
+
}
|
|
36748
|
+
}
|
|
36749
|
+
return;
|
|
36750
|
+
}
|
|
36751
|
+
getRowSize(sheetId, row) {
|
|
36752
|
+
return Math.round(this.getters.getUserRowSize(sheetId, row) ??
|
|
36753
|
+
this.tallestCellInRow[sheetId][row]?.size ??
|
|
36754
|
+
DEFAULT_CELL_HEIGHT);
|
|
36755
|
+
}
|
|
36756
|
+
updateRowSizeForCellChange(sheetId, row, col) {
|
|
36757
|
+
const tallestCellInRow = this.tallestCellInRow[sheetId]?.[row];
|
|
36758
|
+
if (tallestCellInRow?.cell.col === col) {
|
|
36759
|
+
const newTallestCell = this.getRowTallestCell(sheetId, row);
|
|
36760
|
+
this.history.update("tallestCellInRow", sheetId, row, newTallestCell);
|
|
36761
|
+
}
|
|
36762
|
+
const updatedCellHeight = this.getCellHeight({ sheetId, col, row });
|
|
36763
|
+
if (updatedCellHeight <= DEFAULT_CELL_HEIGHT) {
|
|
36764
|
+
return;
|
|
36765
|
+
}
|
|
36766
|
+
if ((!tallestCellInRow && updatedCellHeight > DEFAULT_CELL_HEIGHT) ||
|
|
36767
|
+
(tallestCellInRow && updatedCellHeight > tallestCellInRow.size)) {
|
|
36768
|
+
const newTallestCell = { cell: { sheetId, col, row }, size: updatedCellHeight };
|
|
36769
|
+
this.history.update("tallestCellInRow", sheetId, row, newTallestCell);
|
|
36770
|
+
}
|
|
36771
|
+
}
|
|
36772
|
+
initializeSheet(sheetId) {
|
|
36773
|
+
const tallestCells = [];
|
|
36774
|
+
for (let row = 0; row < this.getters.getNumberRows(sheetId); row++) {
|
|
36775
|
+
const tallestCell = this.getRowTallestCell(sheetId, row);
|
|
36776
|
+
tallestCells.push(tallestCell);
|
|
36777
|
+
}
|
|
36778
|
+
this.history.update("tallestCellInRow", sheetId, tallestCells);
|
|
36779
|
+
}
|
|
36780
|
+
/**
|
|
36781
|
+
* Return the height the cell should have in the sheet, which is either DEFAULT_CELL_HEIGHT if the cell is in a multi-row
|
|
36782
|
+
* merge, or the height of the cell computed based on its style/content.
|
|
36783
|
+
*/
|
|
36784
|
+
getCellHeight(position) {
|
|
36785
|
+
if (this.isInMultiRowMerge(position)) {
|
|
36786
|
+
return DEFAULT_CELL_HEIGHT;
|
|
36787
|
+
}
|
|
36788
|
+
const cell = this.getters.getCell(position);
|
|
36789
|
+
const colSize = this.getters.getColSize(position.sheetId, position.col);
|
|
36790
|
+
return getDefaultCellHeight(this.ctx, cell, colSize);
|
|
36791
|
+
}
|
|
36792
|
+
isInMultiRowMerge(position) {
|
|
36793
|
+
const merge = this.getters.getMerge(position);
|
|
36794
|
+
return !!merge && merge.bottom !== merge.top;
|
|
36795
|
+
}
|
|
36796
|
+
/**
|
|
36797
|
+
* Get the tallest cell of a row and its size.
|
|
36798
|
+
*/
|
|
36799
|
+
getRowTallestCell(sheetId, row) {
|
|
36800
|
+
const userRowSize = this.getters.getUserRowSize(sheetId, row);
|
|
36801
|
+
if (userRowSize !== undefined) {
|
|
36802
|
+
return undefined;
|
|
36803
|
+
}
|
|
36804
|
+
const cellIds = this.getters.getRowCells(sheetId, row);
|
|
36805
|
+
let maxHeight = 0;
|
|
36806
|
+
let tallestCell = undefined;
|
|
36807
|
+
for (let i = 0; i < cellIds.length; i++) {
|
|
36808
|
+
const cell = this.getters.getCellById(cellIds[i]);
|
|
36809
|
+
if (!cell) {
|
|
36810
|
+
continue;
|
|
36811
|
+
}
|
|
36812
|
+
const position = this.getters.getCellPosition(cell.id);
|
|
36813
|
+
const cellHeight = this.getCellHeight(position);
|
|
36814
|
+
if (cellHeight > maxHeight && cellHeight > DEFAULT_CELL_HEIGHT) {
|
|
36815
|
+
maxHeight = cellHeight;
|
|
36816
|
+
tallestCell = { cell: position, size: cellHeight };
|
|
36817
|
+
}
|
|
36818
|
+
}
|
|
36819
|
+
if (tallestCell && tallestCell.size > DEFAULT_CELL_HEIGHT) {
|
|
36820
|
+
return tallestCell;
|
|
36821
|
+
}
|
|
36822
|
+
return undefined;
|
|
36823
|
+
}
|
|
36824
|
+
}
|
|
36825
|
+
|
|
36598
36826
|
/**
|
|
36599
36827
|
* This plugin manage the autofill.
|
|
36600
36828
|
*
|
|
@@ -38296,6 +38524,7 @@ class FindAndReplacePlugin extends UIPlugin {
|
|
|
38296
38524
|
searchFormulas: false,
|
|
38297
38525
|
};
|
|
38298
38526
|
toSearch = "";
|
|
38527
|
+
isSearchDirty = false;
|
|
38299
38528
|
// ---------------------------------------------------------------------------
|
|
38300
38529
|
// Command Handling
|
|
38301
38530
|
// ---------------------------------------------------------------------------
|
|
@@ -38323,14 +38552,21 @@ class FindAndReplacePlugin extends UIPlugin {
|
|
|
38323
38552
|
case "REDO":
|
|
38324
38553
|
case "REMOVE_COLUMNS_ROWS":
|
|
38325
38554
|
case "ADD_COLUMNS_ROWS":
|
|
38326
|
-
|
|
38555
|
+
case "EVALUATE_CELLS":
|
|
38556
|
+
case "UPDATE_CELL":
|
|
38557
|
+
this.isSearchDirty = true;
|
|
38327
38558
|
break;
|
|
38328
38559
|
case "ACTIVATE_SHEET":
|
|
38329
|
-
case "REFRESH_SEARCH":
|
|
38330
38560
|
this.refreshSearch();
|
|
38331
38561
|
break;
|
|
38332
38562
|
}
|
|
38333
38563
|
}
|
|
38564
|
+
finalize() {
|
|
38565
|
+
if (this.isSearchDirty) {
|
|
38566
|
+
this.refreshSearch();
|
|
38567
|
+
this.isSearchDirty = false;
|
|
38568
|
+
}
|
|
38569
|
+
}
|
|
38334
38570
|
// ---------------------------------------------------------------------------
|
|
38335
38571
|
// Getters
|
|
38336
38572
|
// ---------------------------------------------------------------------------
|
|
@@ -38386,6 +38622,11 @@ class FindAndReplacePlugin extends UIPlugin {
|
|
|
38386
38622
|
if (this.toSearch) {
|
|
38387
38623
|
for (const cell of Object.values(cells)) {
|
|
38388
38624
|
const { col, row } = this.getters.getCellPosition(cell.id);
|
|
38625
|
+
const isColHidden = this.getters.isColHidden(sheetId, col);
|
|
38626
|
+
const isRowHidden = this.getters.isRowHidden(sheetId, row);
|
|
38627
|
+
if (isColHidden || isRowHidden) {
|
|
38628
|
+
continue;
|
|
38629
|
+
}
|
|
38389
38630
|
if (cell &&
|
|
38390
38631
|
this.currentSearchRegex &&
|
|
38391
38632
|
this.currentSearchRegex.test(this.getSearchableString({ sheetId, col, row }))) {
|
|
@@ -40028,10 +40269,8 @@ class SortPlugin extends UIPlugin {
|
|
|
40028
40269
|
}
|
|
40029
40270
|
updateCellCommands.push(newCellValues);
|
|
40030
40271
|
}
|
|
40031
|
-
for (const cmd of updateCellCommands) {
|
|
40032
|
-
this.dispatch("UPDATE_CELL", cmd);
|
|
40033
|
-
}
|
|
40034
40272
|
}
|
|
40273
|
+
updateCellCommands.forEach((cmdPayload) => this.dispatch("UPDATE_CELL", cmdPayload));
|
|
40035
40274
|
}
|
|
40036
40275
|
/**
|
|
40037
40276
|
* Return the distances between main merge cells in the zone.
|
|
@@ -40132,24 +40371,28 @@ class SheetUIPlugin extends UIPlugin {
|
|
|
40132
40371
|
// Getters
|
|
40133
40372
|
// ---------------------------------------------------------------------------
|
|
40134
40373
|
getCellWidth(position) {
|
|
40135
|
-
const text = this.getCellText(position);
|
|
40136
40374
|
const style = this.getters.getCellComputedStyle(position);
|
|
40137
|
-
|
|
40138
|
-
|
|
40375
|
+
let contentWidth = 0;
|
|
40376
|
+
const content = this.getters.getEvaluatedCell(position).formattedValue;
|
|
40377
|
+
if (content) {
|
|
40378
|
+
const multiLineText = splitTextToWidth(this.ctx, content, style, undefined);
|
|
40379
|
+
contentWidth += Math.max(...multiLineText.map((line) => computeTextWidth(this.ctx, line, style)));
|
|
40380
|
+
}
|
|
40139
40381
|
const icon = this.getters.getConditionalIcon(position);
|
|
40140
40382
|
if (icon) {
|
|
40141
|
-
contentWidth += computeIconWidth(
|
|
40383
|
+
contentWidth += computeIconWidth(style);
|
|
40142
40384
|
}
|
|
40143
40385
|
const isFilterHeader = this.getters.isFilterHeader(position);
|
|
40144
40386
|
if (isFilterHeader) {
|
|
40145
40387
|
contentWidth += ICON_EDGE_LENGTH + FILTER_ICON_MARGIN;
|
|
40146
40388
|
}
|
|
40147
|
-
if (contentWidth
|
|
40148
|
-
|
|
40149
|
-
|
|
40150
|
-
|
|
40151
|
-
|
|
40152
|
-
|
|
40389
|
+
if (contentWidth === 0) {
|
|
40390
|
+
return 0;
|
|
40391
|
+
}
|
|
40392
|
+
contentWidth += 2 * PADDING_AUTORESIZE_HORIZONTAL;
|
|
40393
|
+
if (style.wrapping === "wrap") {
|
|
40394
|
+
const colWidth = this.getters.getColSize(this.getters.getActiveSheetId(), position.col);
|
|
40395
|
+
return Math.min(colWidth, contentWidth);
|
|
40153
40396
|
}
|
|
40154
40397
|
return contentWidth;
|
|
40155
40398
|
}
|
|
@@ -40172,56 +40415,7 @@ class SheetUIPlugin extends UIPlugin {
|
|
|
40172
40415
|
getCellMultiLineText(position, width) {
|
|
40173
40416
|
const style = this.getters.getCellStyle(position);
|
|
40174
40417
|
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;
|
|
40418
|
+
return splitTextToWidth(this.ctx, text, style, width);
|
|
40225
40419
|
}
|
|
40226
40420
|
/**
|
|
40227
40421
|
* Returns the size, start and end coordinates of a column on an unfolded sheet
|
|
@@ -40280,26 +40474,6 @@ class SheetUIPlugin extends UIPlugin {
|
|
|
40280
40474
|
const sizes = cellsPositions.map((position) => this.getCellWidth({ sheetId, ...position }));
|
|
40281
40475
|
return Math.max(0, ...sizes);
|
|
40282
40476
|
}
|
|
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
40477
|
/**
|
|
40304
40478
|
* Check that any "sheetId" in the command matches an existing
|
|
40305
40479
|
* sheet.
|
|
@@ -41291,7 +41465,7 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
|
|
|
41291
41465
|
.join("\n") || "\t");
|
|
41292
41466
|
}
|
|
41293
41467
|
getHTMLContent() {
|
|
41294
|
-
if (this.cells.length
|
|
41468
|
+
if (this.cells.length === 1 && this.cells[0].length === 1) {
|
|
41295
41469
|
return this.getters.getCellText(this.cells[0][0].position);
|
|
41296
41470
|
}
|
|
41297
41471
|
let htmlTable = '<table border="1" style="border-collapse:collapse">';
|
|
@@ -41616,7 +41790,7 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
41616
41790
|
status = "invisible";
|
|
41617
41791
|
state;
|
|
41618
41792
|
lastPasteState;
|
|
41619
|
-
|
|
41793
|
+
paintFormatStatus = "inactive";
|
|
41620
41794
|
originSheetId;
|
|
41621
41795
|
// ---------------------------------------------------------------------------
|
|
41622
41796
|
// Command Handling
|
|
@@ -41631,7 +41805,7 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
41631
41805
|
if (!this.state) {
|
|
41632
41806
|
return 24 /* CommandResult.EmptyClipboard */;
|
|
41633
41807
|
}
|
|
41634
|
-
const pasteOption = cmd.pasteOption || (this.
|
|
41808
|
+
const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
|
|
41635
41809
|
return this.state.isPasteAllowed(cmd.target, { pasteOption });
|
|
41636
41810
|
case "PASTE_FROM_OS_CLIPBOARD": {
|
|
41637
41811
|
const state = new ClipboardOsState(cmd.text, this.getters, this.dispatch, this.selection);
|
|
@@ -41647,6 +41821,11 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
41647
41821
|
const state = this.getClipboardStateForCopyCells(cut, "CUT");
|
|
41648
41822
|
return state.isPasteAllowed(paste);
|
|
41649
41823
|
}
|
|
41824
|
+
case "ACTIVATE_PAINT_FORMAT": {
|
|
41825
|
+
if (this.paintFormatStatus !== "inactive") {
|
|
41826
|
+
return 95 /* CommandResult.AlreadyInPaintingFormatMode */;
|
|
41827
|
+
}
|
|
41828
|
+
}
|
|
41650
41829
|
}
|
|
41651
41830
|
return 0 /* CommandResult.Success */;
|
|
41652
41831
|
}
|
|
@@ -41663,11 +41842,13 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
41663
41842
|
if (!this.state) {
|
|
41664
41843
|
break;
|
|
41665
41844
|
}
|
|
41666
|
-
const pasteOption = cmd.pasteOption || (this.
|
|
41667
|
-
this._isPaintingFormat = false;
|
|
41845
|
+
const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
|
|
41668
41846
|
this.state.paste(cmd.target, { pasteOption, shouldPasteCF: true, selectTarget: true });
|
|
41669
41847
|
this.lastPasteState = this.state;
|
|
41670
|
-
this.
|
|
41848
|
+
if (this.paintFormatStatus === "oneOff") {
|
|
41849
|
+
this.paintFormatStatus = "inactive";
|
|
41850
|
+
this.status = "invisible";
|
|
41851
|
+
}
|
|
41671
41852
|
break;
|
|
41672
41853
|
case "CLEAN_CLIPBOARD_HIGHLIGHT":
|
|
41673
41854
|
this.status = "invisible";
|
|
@@ -41735,8 +41916,13 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
41735
41916
|
case "ACTIVATE_PAINT_FORMAT": {
|
|
41736
41917
|
const zones = this.getters.getSelectedZones();
|
|
41737
41918
|
this.state = this.getClipboardStateForCopyCells(zones, "COPY");
|
|
41738
|
-
this._isPaintingFormat = true;
|
|
41739
41919
|
this.status = "visible";
|
|
41920
|
+
if (cmd.persistent) {
|
|
41921
|
+
this.paintFormatStatus = "persistent";
|
|
41922
|
+
}
|
|
41923
|
+
else {
|
|
41924
|
+
this.paintFormatStatus = "oneOff";
|
|
41925
|
+
}
|
|
41740
41926
|
break;
|
|
41741
41927
|
}
|
|
41742
41928
|
case "DELETE_SHEET":
|
|
@@ -41748,6 +41934,11 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
41748
41934
|
this.status = "invisible";
|
|
41749
41935
|
}
|
|
41750
41936
|
break;
|
|
41937
|
+
case "CANCEL_PAINT_FORMAT": {
|
|
41938
|
+
this.paintFormatStatus = "inactive";
|
|
41939
|
+
this.status = "invisible";
|
|
41940
|
+
break;
|
|
41941
|
+
}
|
|
41751
41942
|
default:
|
|
41752
41943
|
if (isCoreCommand(cmd)) {
|
|
41753
41944
|
this.status = "invisible";
|
|
@@ -41778,7 +41969,7 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
41778
41969
|
return this.state ? this.state.operation === "CUT" : false;
|
|
41779
41970
|
}
|
|
41780
41971
|
isPaintingFormat() {
|
|
41781
|
-
return this.
|
|
41972
|
+
return this.paintFormatStatus !== "inactive";
|
|
41782
41973
|
}
|
|
41783
41974
|
// ---------------------------------------------------------------------------
|
|
41784
41975
|
// Private methods
|
|
@@ -44413,6 +44604,7 @@ const coreViewsPluginRegistry = new Registry()
|
|
|
44413
44604
|
.add("evaluation", EvaluationPlugin)
|
|
44414
44605
|
.add("evaluation_chart", EvaluationChartPlugin)
|
|
44415
44606
|
.add("evaluation_cf", EvaluationConditionalFormatPlugin)
|
|
44607
|
+
.add("row_size", UIRowSizePlugin)
|
|
44416
44608
|
.add("custom_colors", CustomColorsPlugin);
|
|
44417
44609
|
|
|
44418
44610
|
const clickableCellRegistry = new Registry();
|
|
@@ -45535,6 +45727,11 @@ css /* scss */ `
|
|
|
45535
45727
|
.o-sidePanelButton:enabled {
|
|
45536
45728
|
cursor: pointer;
|
|
45537
45729
|
}
|
|
45730
|
+
|
|
45731
|
+
.o-sidePanelButton:disabled {
|
|
45732
|
+
color: ${DISABLED_TEXT_COLOR};
|
|
45733
|
+
}
|
|
45734
|
+
|
|
45538
45735
|
.o-sidePanelButton:last-child {
|
|
45539
45736
|
margin-right: 0px;
|
|
45540
45737
|
}
|
|
@@ -45668,11 +45865,11 @@ class ActionButton extends Component {
|
|
|
45668
45865
|
}
|
|
45669
45866
|
get title() {
|
|
45670
45867
|
const name = this.actionButton.name(this.env);
|
|
45671
|
-
const description = this.actionButton.description;
|
|
45868
|
+
const description = this.actionButton.description(this.env);
|
|
45672
45869
|
return name + (description ? ` (${description})` : "");
|
|
45673
45870
|
}
|
|
45674
45871
|
get iconTitle() {
|
|
45675
|
-
return this.actionButton.icon;
|
|
45872
|
+
return this.actionButton.icon(this.env);
|
|
45676
45873
|
}
|
|
45677
45874
|
onClick(ev) {
|
|
45678
45875
|
if (this.isEnabled) {
|
|
@@ -46057,6 +46254,27 @@ FontSizeEditor.props = {
|
|
|
46057
46254
|
class: String,
|
|
46058
46255
|
};
|
|
46059
46256
|
|
|
46257
|
+
class PaintFormatButton extends Component {
|
|
46258
|
+
static template = "o-spreadsheet-PaintFormatButton";
|
|
46259
|
+
get isActive() {
|
|
46260
|
+
return this.env.model.getters.isPaintingFormat();
|
|
46261
|
+
}
|
|
46262
|
+
onDblClick() {
|
|
46263
|
+
this.env.model.dispatch("ACTIVATE_PAINT_FORMAT", { persistent: true });
|
|
46264
|
+
}
|
|
46265
|
+
togglePaintFormat() {
|
|
46266
|
+
if (this.isActive) {
|
|
46267
|
+
this.env.model.dispatch("CANCEL_PAINT_FORMAT");
|
|
46268
|
+
}
|
|
46269
|
+
else {
|
|
46270
|
+
this.env.model.dispatch("ACTIVATE_PAINT_FORMAT", { persistent: false });
|
|
46271
|
+
}
|
|
46272
|
+
}
|
|
46273
|
+
}
|
|
46274
|
+
PaintFormatButton.props = {
|
|
46275
|
+
class: { type: String, optional: true },
|
|
46276
|
+
};
|
|
46277
|
+
|
|
46060
46278
|
// -----------------------------------------------------------------------------
|
|
46061
46279
|
// TopBar
|
|
46062
46280
|
// -----------------------------------------------------------------------------
|
|
@@ -46157,6 +46375,7 @@ class TopBar extends Component {
|
|
|
46157
46375
|
TopBarComposer,
|
|
46158
46376
|
FontSizeEditor,
|
|
46159
46377
|
ActionButton,
|
|
46378
|
+
PaintFormatButton,
|
|
46160
46379
|
BorderEditorWidget,
|
|
46161
46380
|
};
|
|
46162
46381
|
state = useState({
|
|
@@ -48009,7 +48228,7 @@ class SelectionStreamProcessorImpl {
|
|
|
48009
48228
|
: "nextCluster";
|
|
48010
48229
|
while (true) {
|
|
48011
48230
|
const nextCellPosition = this.getNextCellPosition(currentPosition, dim, dir);
|
|
48012
|
-
// Break if nextPosition
|
|
48231
|
+
// Break if nextPosition === currentPosition, which happens if there's no next valid position
|
|
48013
48232
|
if (currentPosition.col === nextCellPosition.col &&
|
|
48014
48233
|
currentPosition.row === nextCellPosition.row) {
|
|
48015
48234
|
break;
|
|
@@ -49923,6 +50142,7 @@ class Model extends EventBus {
|
|
|
49923
50142
|
...config,
|
|
49924
50143
|
mode: config.mode || "normal",
|
|
49925
50144
|
custom: config.custom || {},
|
|
50145
|
+
defaultCurrencyFormat: config.defaultCurrencyFormat || "[$$]#,##0.00",
|
|
49926
50146
|
external: this.setupExternalConfig(config.external || {}),
|
|
49927
50147
|
transportService,
|
|
49928
50148
|
client,
|
|
@@ -50220,6 +50440,7 @@ const helpers = {
|
|
|
50220
50440
|
numberToLetters,
|
|
50221
50441
|
UuidGenerator,
|
|
50222
50442
|
formatValue,
|
|
50443
|
+
createCurrencyFormat,
|
|
50223
50444
|
computeTextWidth,
|
|
50224
50445
|
createEmptyWorkbookData,
|
|
50225
50446
|
createEmptySheet,
|
|
@@ -50271,6 +50492,6 @@ const constants = {
|
|
|
50271
50492
|
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
50493
|
|
|
50273
50494
|
|
|
50274
|
-
__info__.version = '16.4.
|
|
50275
|
-
__info__.date = '2023-07-
|
|
50276
|
-
__info__.hash = '
|
|
50495
|
+
__info__.version = '16.4.1';
|
|
50496
|
+
__info__.date = '2023-07-26T12:13:04.992Z';
|
|
50497
|
+
__info__.hash = 'e687fa9';
|