@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
|
@@ -109,8 +109,8 @@
|
|
|
109
109
|
const HEADER_BORDER_COLOR = "#C0C0C0";
|
|
110
110
|
const CELL_BORDER_COLOR = "#E2E3E3";
|
|
111
111
|
const BACKGROUND_CHART_COLOR = "#FFFFFF";
|
|
112
|
-
const MENU_ITEM_DISABLED_COLOR = "#CACACA";
|
|
113
112
|
const BG_HOVER_COLOR = "#EBEBEB";
|
|
113
|
+
const DISABLED_TEXT_COLOR = "#CACACA";
|
|
114
114
|
const DEFAULT_COLOR_SCALE_MIDPOINT_COLOR = 0xb6d7a8;
|
|
115
115
|
const LINK_COLOR = "#01666b";
|
|
116
116
|
const FILTERS_COLOR = "#188038";
|
|
@@ -236,6 +236,7 @@
|
|
|
236
236
|
const HEADER_FONT_SIZE = 11;
|
|
237
237
|
const DEFAULT_FONT = "'Roboto', arial";
|
|
238
238
|
const DEFAULT_VERTICAL_ALIGN = "bottom";
|
|
239
|
+
const DEFAULT_WRAPPING_MODE = "overflow";
|
|
239
240
|
// Borders
|
|
240
241
|
const DEFAULT_BORDER_DESC = { style: "thin", color: "#000000" };
|
|
241
242
|
const DEFAULT_FILTER_BORDER_DESC = { style: "thin", color: FILTERS_COLOR };
|
|
@@ -393,82 +394,6 @@
|
|
|
393
394
|
function clip(val, min, max) {
|
|
394
395
|
return val < min ? min : val > max ? max : val;
|
|
395
396
|
}
|
|
396
|
-
function computeTextLinesHeight(textLineHeight, numberOfLines = 1) {
|
|
397
|
-
return numberOfLines * (textLineHeight + MIN_CELL_TEXT_MARGIN) - MIN_CELL_TEXT_MARGIN;
|
|
398
|
-
}
|
|
399
|
-
/**
|
|
400
|
-
* Get the default height of the cell given its style.
|
|
401
|
-
*/
|
|
402
|
-
function getDefaultCellHeight(cell) {
|
|
403
|
-
if (!cell || !cell.content) {
|
|
404
|
-
return DEFAULT_CELL_HEIGHT;
|
|
405
|
-
}
|
|
406
|
-
const fontSize = computeTextFontSizeInPixels(cell.style);
|
|
407
|
-
// the number of lines should be computed from the formula result, but it's not evaluated at this point
|
|
408
|
-
const numberOfLines = cell.isFormula ? 1 : cell.content.split(NEWLINE).length;
|
|
409
|
-
return computeTextLinesHeight(fontSize, numberOfLines) + 2 * PADDING_AUTORESIZE_VERTICAL;
|
|
410
|
-
}
|
|
411
|
-
function computeTextWidth(context, text, style) {
|
|
412
|
-
const font = computeTextFont(style);
|
|
413
|
-
if (!textWidthCache[font]) {
|
|
414
|
-
textWidthCache[font] = {};
|
|
415
|
-
}
|
|
416
|
-
if (textWidthCache[font][text] === undefined) {
|
|
417
|
-
context.save();
|
|
418
|
-
context.font = font;
|
|
419
|
-
const textWidth = context.measureText(text).width;
|
|
420
|
-
context.restore();
|
|
421
|
-
textWidthCache[font][text] = textWidth;
|
|
422
|
-
}
|
|
423
|
-
return textWidthCache[font][text];
|
|
424
|
-
}
|
|
425
|
-
const textWidthCache = {};
|
|
426
|
-
function fontSizeInPixels(fontSize) {
|
|
427
|
-
return Math.round((fontSize * 96) / 72);
|
|
428
|
-
}
|
|
429
|
-
function computeTextFont(style) {
|
|
430
|
-
const italic = style.italic ? "italic " : "";
|
|
431
|
-
const weight = style.bold ? "bold" : DEFAULT_FONT_WEIGHT;
|
|
432
|
-
const size = computeTextFontSizeInPixels(style);
|
|
433
|
-
return `${italic}${weight} ${size}px ${DEFAULT_FONT}`;
|
|
434
|
-
}
|
|
435
|
-
function computeTextFontSizeInPixels(style) {
|
|
436
|
-
const sizeInPt = style?.fontSize || DEFAULT_FONT_SIZE;
|
|
437
|
-
return fontSizeInPixels(sizeInPt);
|
|
438
|
-
}
|
|
439
|
-
/**
|
|
440
|
-
* Return the font size that makes the width of a text match the given line width.
|
|
441
|
-
* Minimum font size is 1.
|
|
442
|
-
*
|
|
443
|
-
* @param getTextWidth function that takes a fontSize as argument, and return the width of the text with this font size.
|
|
444
|
-
*/
|
|
445
|
-
function getFontSizeMatchingWidth(lineWidth, maxFontSize, getTextWidth, precision = 0.25) {
|
|
446
|
-
let minFontSize = 1;
|
|
447
|
-
if (getTextWidth(minFontSize) > lineWidth)
|
|
448
|
-
return minFontSize;
|
|
449
|
-
if (getTextWidth(maxFontSize) < lineWidth)
|
|
450
|
-
return maxFontSize;
|
|
451
|
-
// Dichotomic search
|
|
452
|
-
let fontSize = (minFontSize + maxFontSize) / 2;
|
|
453
|
-
let currentTextWidth = getTextWidth(fontSize);
|
|
454
|
-
// Use a maximum number of iterations to be safe, because measuring text isn't 100% precise
|
|
455
|
-
let iterations = 0;
|
|
456
|
-
while (Math.abs(currentTextWidth - lineWidth) > precision && iterations < 20) {
|
|
457
|
-
if (currentTextWidth >= lineWidth) {
|
|
458
|
-
maxFontSize = (minFontSize + maxFontSize) / 2;
|
|
459
|
-
}
|
|
460
|
-
else {
|
|
461
|
-
minFontSize = (minFontSize + maxFontSize) / 2;
|
|
462
|
-
}
|
|
463
|
-
fontSize = (minFontSize + maxFontSize) / 2;
|
|
464
|
-
currentTextWidth = getTextWidth(fontSize);
|
|
465
|
-
iterations++;
|
|
466
|
-
}
|
|
467
|
-
return fontSize;
|
|
468
|
-
}
|
|
469
|
-
function computeIconWidth(style) {
|
|
470
|
-
return computeTextFontSizeInPixels(style) + 2 * MIN_CF_ICON_MARGIN;
|
|
471
|
-
}
|
|
472
397
|
/**
|
|
473
398
|
* Create a range from start (included) to end (excluded).
|
|
474
399
|
* range(10, 13) => [10, 11, 12]
|
|
@@ -723,10 +648,6 @@
|
|
|
723
648
|
Object.keys(cleanObject).forEach((key) => !cleanObject[key] && delete cleanObject[key]);
|
|
724
649
|
return cleanObject;
|
|
725
650
|
}
|
|
726
|
-
/** Transform a string to lower case. If the string is undefined, return an empty string */
|
|
727
|
-
function toLowerCase(str) {
|
|
728
|
-
return str ? str.toLowerCase() : "";
|
|
729
|
-
}
|
|
730
651
|
function transpose2dArray(matrix, callback = (val) => val) {
|
|
731
652
|
if (!matrix.length)
|
|
732
653
|
return [];
|
|
@@ -815,6 +736,14 @@
|
|
|
815
736
|
return cache.get(args[0]);
|
|
816
737
|
},
|
|
817
738
|
}[funcName];
|
|
739
|
+
}
|
|
740
|
+
function removeIndexesFromArray(array, indexes) {
|
|
741
|
+
return array.filter((_, index) => !indexes.includes(index));
|
|
742
|
+
}
|
|
743
|
+
function insertItemsAtIndex(array, items, index) {
|
|
744
|
+
const newArray = [...array];
|
|
745
|
+
newArray.splice(index, 0, ...items);
|
|
746
|
+
return newArray;
|
|
818
747
|
}
|
|
819
748
|
|
|
820
749
|
const RBA_REGEX = /rgba?\(|\s+|\)/gi;
|
|
@@ -958,13 +887,13 @@
|
|
|
958
887
|
let g = rgba.g.toString(16);
|
|
959
888
|
let b = rgba.b.toString(16);
|
|
960
889
|
let a = Math.round(rgba.a * 255).toString(16);
|
|
961
|
-
if (r.length
|
|
890
|
+
if (r.length === 1)
|
|
962
891
|
r = "0" + r;
|
|
963
|
-
if (g.length
|
|
892
|
+
if (g.length === 1)
|
|
964
893
|
g = "0" + g;
|
|
965
|
-
if (b.length
|
|
894
|
+
if (b.length === 1)
|
|
966
895
|
b = "0" + b;
|
|
967
|
-
if (a.length
|
|
896
|
+
if (a.length === 1)
|
|
968
897
|
a = "0" + a;
|
|
969
898
|
if (a === "ff")
|
|
970
899
|
a = "";
|
|
@@ -1067,13 +996,13 @@
|
|
|
1067
996
|
let l = 0;
|
|
1068
997
|
// Calculate hue
|
|
1069
998
|
// No difference
|
|
1070
|
-
if (delta
|
|
999
|
+
if (delta === 0)
|
|
1071
1000
|
h = 0;
|
|
1072
1001
|
// Red is max
|
|
1073
|
-
else if (cMax
|
|
1002
|
+
else if (cMax === r)
|
|
1074
1003
|
h = ((g - b) / delta) % 6;
|
|
1075
1004
|
// Green is max
|
|
1076
|
-
else if (cMax
|
|
1005
|
+
else if (cMax === g)
|
|
1077
1006
|
h = (b - r) / delta + 2;
|
|
1078
1007
|
// Blue is max
|
|
1079
1008
|
else
|
|
@@ -1084,7 +1013,7 @@
|
|
|
1084
1013
|
h += 360;
|
|
1085
1014
|
l = (cMax + cMin) / 2;
|
|
1086
1015
|
// Calculate saturation
|
|
1087
|
-
s = delta
|
|
1016
|
+
s = delta === 0 ? 0 : delta / (1 - Math.abs(2 * l - 1));
|
|
1088
1017
|
// Multiply l and s by 100
|
|
1089
1018
|
s = +(s * 100).toFixed(1);
|
|
1090
1019
|
l = +(l * 100).toFixed(1);
|
|
@@ -1521,7 +1450,7 @@
|
|
|
1521
1450
|
}
|
|
1522
1451
|
function isLeapYear(year) {
|
|
1523
1452
|
const _year = Math.trunc(year);
|
|
1524
|
-
return (_year % 4 === 0 && _year % 100 != 0) || _year % 400
|
|
1453
|
+
return (_year % 4 === 0 && _year % 100 != 0) || _year % 400 === 0;
|
|
1525
1454
|
}
|
|
1526
1455
|
function getYearFrac(startDate, endDate, _dayCountConvention) {
|
|
1527
1456
|
if (startDate === endDate) {
|
|
@@ -2182,6 +2111,39 @@
|
|
|
2182
2111
|
}
|
|
2183
2112
|
return undefined;
|
|
2184
2113
|
}
|
|
2114
|
+
function createCurrencyFormat(currency) {
|
|
2115
|
+
const decimalPlaces = currency.decimalPlaces ?? 2;
|
|
2116
|
+
const position = currency.position ?? "before";
|
|
2117
|
+
const code = currency.code ?? "";
|
|
2118
|
+
const symbol = currency.symbol ?? "";
|
|
2119
|
+
const decimalRepresentation = decimalPlaces ? "." + "0".repeat(decimalPlaces) : "";
|
|
2120
|
+
const numberFormat = "#,##0" + decimalRepresentation;
|
|
2121
|
+
let textExpression = `${code} ${symbol}`.trim();
|
|
2122
|
+
if (position === "after" && code) {
|
|
2123
|
+
textExpression = " " + textExpression;
|
|
2124
|
+
}
|
|
2125
|
+
return insertTextInFormat(textExpression, position, numberFormat);
|
|
2126
|
+
}
|
|
2127
|
+
function insertTextInFormat(text, position, format) {
|
|
2128
|
+
const textExpression = `[$${text}]`;
|
|
2129
|
+
return position === "before" ? textExpression + format : format + textExpression;
|
|
2130
|
+
}
|
|
2131
|
+
function roundFormat(format) {
|
|
2132
|
+
const internalFormat = parseFormat(format);
|
|
2133
|
+
const roundedFormat = internalFormat.map((formatPart) => {
|
|
2134
|
+
if (formatPart.type === "NUMBER") {
|
|
2135
|
+
return {
|
|
2136
|
+
type: formatPart.type,
|
|
2137
|
+
format: {
|
|
2138
|
+
...formatPart.format,
|
|
2139
|
+
decimalPart: undefined,
|
|
2140
|
+
},
|
|
2141
|
+
};
|
|
2142
|
+
}
|
|
2143
|
+
return formatPart;
|
|
2144
|
+
});
|
|
2145
|
+
return convertInternalFormatToFormat(roundedFormat);
|
|
2146
|
+
}
|
|
2185
2147
|
function createLargeNumberFormat(format, magnitude, postFix, locale) {
|
|
2186
2148
|
const internalFormat = parseFormat(format || "#,##0");
|
|
2187
2149
|
const largeNumberFormat = internalFormat
|
|
@@ -3275,6 +3237,169 @@
|
|
|
3275
3237
|
return rows;
|
|
3276
3238
|
}
|
|
3277
3239
|
|
|
3240
|
+
function computeTextLinesHeight(textLineHeight, numberOfLines = 1) {
|
|
3241
|
+
return numberOfLines * (textLineHeight + MIN_CELL_TEXT_MARGIN) - MIN_CELL_TEXT_MARGIN;
|
|
3242
|
+
}
|
|
3243
|
+
/**
|
|
3244
|
+
* Get the default height of the cell given its style.
|
|
3245
|
+
*/
|
|
3246
|
+
function getDefaultCellHeight(ctx, cell, colSize) {
|
|
3247
|
+
if (!cell || !cell.content)
|
|
3248
|
+
return DEFAULT_CELL_HEIGHT;
|
|
3249
|
+
const maxWidth = cell.style?.wrapping ? colSize - 2 * MIN_CELL_TEXT_MARGIN : undefined;
|
|
3250
|
+
const numberOfLines = cell.isFormula
|
|
3251
|
+
? 1
|
|
3252
|
+
: splitTextToWidth(ctx, cell.content, cell.style, maxWidth).length;
|
|
3253
|
+
const fontSize = computeTextFontSizeInPixels(cell.style);
|
|
3254
|
+
return computeTextLinesHeight(fontSize, numberOfLines) + 2 * PADDING_AUTORESIZE_VERTICAL;
|
|
3255
|
+
}
|
|
3256
|
+
const textWidthCache = {};
|
|
3257
|
+
function computeTextWidth(context, text, style) {
|
|
3258
|
+
const font = computeTextFont(style);
|
|
3259
|
+
if (!textWidthCache[font]) {
|
|
3260
|
+
textWidthCache[font] = {};
|
|
3261
|
+
}
|
|
3262
|
+
if (textWidthCache[font][text] === undefined) {
|
|
3263
|
+
context.save();
|
|
3264
|
+
context.font = font;
|
|
3265
|
+
const textWidth = context.measureText(text).width;
|
|
3266
|
+
context.restore();
|
|
3267
|
+
textWidthCache[font][text] = textWidth;
|
|
3268
|
+
}
|
|
3269
|
+
return textWidthCache[font][text];
|
|
3270
|
+
}
|
|
3271
|
+
function fontSizeInPixels(fontSize) {
|
|
3272
|
+
return Math.round((fontSize * 96) / 72);
|
|
3273
|
+
}
|
|
3274
|
+
function computeTextFont(style) {
|
|
3275
|
+
const italic = style.italic ? "italic " : "";
|
|
3276
|
+
const weight = style.bold ? "bold" : DEFAULT_FONT_WEIGHT;
|
|
3277
|
+
const size = computeTextFontSizeInPixels(style);
|
|
3278
|
+
return `${italic}${weight} ${size}px ${DEFAULT_FONT}`;
|
|
3279
|
+
}
|
|
3280
|
+
function computeTextFontSizeInPixels(style) {
|
|
3281
|
+
const sizeInPt = style?.fontSize || DEFAULT_FONT_SIZE;
|
|
3282
|
+
return fontSizeInPixels(sizeInPt);
|
|
3283
|
+
}
|
|
3284
|
+
function splitWordToSpecificWidth(ctx, word, width, style) {
|
|
3285
|
+
const wordWidth = computeTextWidth(ctx, word, style);
|
|
3286
|
+
if (wordWidth <= width) {
|
|
3287
|
+
return [word];
|
|
3288
|
+
}
|
|
3289
|
+
const splitWord = [];
|
|
3290
|
+
let wordPart = "";
|
|
3291
|
+
for (let l of word) {
|
|
3292
|
+
const wordPartWidth = computeTextWidth(ctx, wordPart + l, style);
|
|
3293
|
+
if (wordPartWidth > width) {
|
|
3294
|
+
splitWord.push(wordPart);
|
|
3295
|
+
wordPart = l;
|
|
3296
|
+
}
|
|
3297
|
+
else {
|
|
3298
|
+
wordPart += l;
|
|
3299
|
+
}
|
|
3300
|
+
}
|
|
3301
|
+
splitWord.push(wordPart);
|
|
3302
|
+
return splitWord;
|
|
3303
|
+
}
|
|
3304
|
+
/**
|
|
3305
|
+
* Return the given text, split in multiple lines if needed. The text will be split in multiple
|
|
3306
|
+
* line if it contains NEWLINE characters, or if it's longer than the given width.
|
|
3307
|
+
*/
|
|
3308
|
+
function splitTextToWidth(ctx, text, style, width) {
|
|
3309
|
+
if (!style)
|
|
3310
|
+
style = {};
|
|
3311
|
+
const brokenText = [];
|
|
3312
|
+
// Checking if text contains NEWLINE before split makes it very slightly slower if text contains it,
|
|
3313
|
+
// but 5-10x faster if it doesn't
|
|
3314
|
+
const lines = text.includes(NEWLINE) ? text.split(NEWLINE) : [text];
|
|
3315
|
+
for (const line of lines) {
|
|
3316
|
+
const words = line.includes(" ") ? line.split(" ") : [line];
|
|
3317
|
+
if (!width) {
|
|
3318
|
+
brokenText.push(line);
|
|
3319
|
+
continue;
|
|
3320
|
+
}
|
|
3321
|
+
let textLine = "";
|
|
3322
|
+
let availableWidth = width;
|
|
3323
|
+
for (let word of words) {
|
|
3324
|
+
const splitWord = splitWordToSpecificWidth(ctx, word, width, style);
|
|
3325
|
+
const lastPart = splitWord.pop();
|
|
3326
|
+
const lastPartWidth = computeTextWidth(ctx, lastPart, style);
|
|
3327
|
+
// At this step: "splitWord" is an array composed of parts of word whose
|
|
3328
|
+
// length is at most equal to "width".
|
|
3329
|
+
// Last part contains the end of the word.
|
|
3330
|
+
// Note that: When word length is less than width, then lastPart is equal
|
|
3331
|
+
// to word and splitWord is empty
|
|
3332
|
+
if (splitWord.length) {
|
|
3333
|
+
if (textLine !== "") {
|
|
3334
|
+
brokenText.push(textLine);
|
|
3335
|
+
textLine = "";
|
|
3336
|
+
availableWidth = width;
|
|
3337
|
+
}
|
|
3338
|
+
splitWord.forEach((wordPart) => {
|
|
3339
|
+
brokenText.push(wordPart);
|
|
3340
|
+
});
|
|
3341
|
+
textLine = lastPart;
|
|
3342
|
+
availableWidth = width - lastPartWidth;
|
|
3343
|
+
}
|
|
3344
|
+
else {
|
|
3345
|
+
// here "lastPart" is equal to "word" and the "word" size is smaller than "width"
|
|
3346
|
+
const _word = textLine === "" ? lastPart : " " + lastPart;
|
|
3347
|
+
const wordWidth = computeTextWidth(ctx, _word, style);
|
|
3348
|
+
if (wordWidth <= availableWidth) {
|
|
3349
|
+
textLine += _word;
|
|
3350
|
+
availableWidth -= wordWidth;
|
|
3351
|
+
}
|
|
3352
|
+
else {
|
|
3353
|
+
brokenText.push(textLine);
|
|
3354
|
+
textLine = lastPart;
|
|
3355
|
+
availableWidth = width - lastPartWidth;
|
|
3356
|
+
}
|
|
3357
|
+
}
|
|
3358
|
+
}
|
|
3359
|
+
if (textLine !== "") {
|
|
3360
|
+
brokenText.push(textLine);
|
|
3361
|
+
}
|
|
3362
|
+
}
|
|
3363
|
+
return brokenText;
|
|
3364
|
+
}
|
|
3365
|
+
/**
|
|
3366
|
+
* Return the font size that makes the width of a text match the given line width.
|
|
3367
|
+
* Minimum font size is 1.
|
|
3368
|
+
*
|
|
3369
|
+
* @param getTextWidth function that takes a fontSize as argument, and return the width of the text with this font size.
|
|
3370
|
+
*/
|
|
3371
|
+
function getFontSizeMatchingWidth(lineWidth, maxFontSize, getTextWidth, precision = 0.25) {
|
|
3372
|
+
let minFontSize = 1;
|
|
3373
|
+
if (getTextWidth(minFontSize) > lineWidth)
|
|
3374
|
+
return minFontSize;
|
|
3375
|
+
if (getTextWidth(maxFontSize) < lineWidth)
|
|
3376
|
+
return maxFontSize;
|
|
3377
|
+
// Dichotomic search
|
|
3378
|
+
let fontSize = (minFontSize + maxFontSize) / 2;
|
|
3379
|
+
let currentTextWidth = getTextWidth(fontSize);
|
|
3380
|
+
// Use a maximum number of iterations to be safe, because measuring text isn't 100% precise
|
|
3381
|
+
let iterations = 0;
|
|
3382
|
+
while (Math.abs(currentTextWidth - lineWidth) > precision && iterations < 20) {
|
|
3383
|
+
if (currentTextWidth >= lineWidth) {
|
|
3384
|
+
maxFontSize = (minFontSize + maxFontSize) / 2;
|
|
3385
|
+
}
|
|
3386
|
+
else {
|
|
3387
|
+
minFontSize = (minFontSize + maxFontSize) / 2;
|
|
3388
|
+
}
|
|
3389
|
+
fontSize = (minFontSize + maxFontSize) / 2;
|
|
3390
|
+
currentTextWidth = getTextWidth(fontSize);
|
|
3391
|
+
iterations++;
|
|
3392
|
+
}
|
|
3393
|
+
return fontSize;
|
|
3394
|
+
}
|
|
3395
|
+
function computeIconWidth(style) {
|
|
3396
|
+
return computeTextFontSizeInPixels(style) + 2 * MIN_CF_ICON_MARGIN;
|
|
3397
|
+
}
|
|
3398
|
+
/** Transform a string to lower case. If the string is undefined, return an empty string */
|
|
3399
|
+
function toLowerCase(str) {
|
|
3400
|
+
return str ? str.toLowerCase() : "";
|
|
3401
|
+
}
|
|
3402
|
+
|
|
3278
3403
|
/*
|
|
3279
3404
|
* https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript
|
|
3280
3405
|
* */
|
|
@@ -3297,7 +3422,7 @@
|
|
|
3297
3422
|
else {
|
|
3298
3423
|
// mainly for jest and other browsers that do not have the crypto functionality
|
|
3299
3424
|
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
|
|
3300
|
-
var r = (Math.random() * 16) | 0, v = c
|
|
3425
|
+
var r = (Math.random() * 16) | 0, v = c === "x" ? r : (r & 0x3) | 0x8;
|
|
3301
3426
|
return v.toString(16);
|
|
3302
3427
|
});
|
|
3303
3428
|
}
|
|
@@ -3927,7 +4052,6 @@
|
|
|
3927
4052
|
"SET_VIEWPORT_OFFSET",
|
|
3928
4053
|
"SELECT_SEARCH_NEXT_MATCH",
|
|
3929
4054
|
"SELECT_SEARCH_PREVIOUS_MATCH",
|
|
3930
|
-
"REFRESH_SEARCH",
|
|
3931
4055
|
"UPDATE_SEARCH",
|
|
3932
4056
|
"CLEAR_SEARCH",
|
|
3933
4057
|
"EVALUATE_CELLS",
|
|
@@ -4125,6 +4249,7 @@
|
|
|
4125
4249
|
CommandResult[CommandResult["NoSplitSeparatorInSelection"] = 92] = "NoSplitSeparatorInSelection";
|
|
4126
4250
|
CommandResult[CommandResult["NoActiveSheet"] = 93] = "NoActiveSheet";
|
|
4127
4251
|
CommandResult[CommandResult["InvalidLocale"] = 94] = "InvalidLocale";
|
|
4252
|
+
CommandResult[CommandResult["AlreadyInPaintingFormatMode"] = 95] = "AlreadyInPaintingFormatMode";
|
|
4128
4253
|
})(exports.CommandResult || (exports.CommandResult = {}));
|
|
4129
4254
|
|
|
4130
4255
|
const borderStyles = ["thin", "medium", "thick", "dashed", "dotted"];
|
|
@@ -5865,7 +5990,7 @@
|
|
|
5865
5990
|
}
|
|
5866
5991
|
}
|
|
5867
5992
|
&.disabled {
|
|
5868
|
-
color: ${
|
|
5993
|
+
color: ${DISABLED_TEXT_COLOR};
|
|
5869
5994
|
cursor: not-allowed;
|
|
5870
5995
|
}
|
|
5871
5996
|
}
|
|
@@ -5940,8 +6065,8 @@
|
|
|
5940
6065
|
return this.props.menuItems.some((menuItem) => !!menuItem.icon || !!menuItem.isActive);
|
|
5941
6066
|
}
|
|
5942
6067
|
getIconName(menu) {
|
|
5943
|
-
if (menu.icon) {
|
|
5944
|
-
return menu.icon;
|
|
6068
|
+
if (menu.icon(this.env)) {
|
|
6069
|
+
return menu.icon(this.env);
|
|
5945
6070
|
}
|
|
5946
6071
|
if (menu.isActive?.(this.env)) {
|
|
5947
6072
|
return "o-spreadsheet-Icon.CHECK";
|
|
@@ -6375,7 +6500,7 @@
|
|
|
6375
6500
|
for (let pivot = 0; pivot < dim; pivot++) {
|
|
6376
6501
|
let diagonalElement = C[pivot][pivot];
|
|
6377
6502
|
// if we have a 0 on the diagonal we'll need to swap with a lower row
|
|
6378
|
-
if (diagonalElement
|
|
6503
|
+
if (diagonalElement === 0) {
|
|
6379
6504
|
//look through every row below the i'th row
|
|
6380
6505
|
for (let row = pivot + 1; row < dim; row++) {
|
|
6381
6506
|
//if the ii'th row has a non-0 in the i'th col, swap it with that row
|
|
@@ -6402,7 +6527,7 @@
|
|
|
6402
6527
|
// the other rows so that there will be 0's in this column in the
|
|
6403
6528
|
// rows above and below this one
|
|
6404
6529
|
for (let row = 0; row < dim; row++) {
|
|
6405
|
-
if (row
|
|
6530
|
+
if (row === pivot) {
|
|
6406
6531
|
continue;
|
|
6407
6532
|
}
|
|
6408
6533
|
// We want to change this element to 0
|
|
@@ -12467,7 +12592,7 @@
|
|
|
12467
12592
|
return false;
|
|
12468
12593
|
}
|
|
12469
12594
|
catch (e) {
|
|
12470
|
-
return e?.errorType
|
|
12595
|
+
return e?.errorType === CellErrorType.NotAvailable;
|
|
12471
12596
|
}
|
|
12472
12597
|
},
|
|
12473
12598
|
isExported: true,
|
|
@@ -15183,6 +15308,8 @@
|
|
|
15183
15308
|
function createAction(item) {
|
|
15184
15309
|
const name = item.name;
|
|
15185
15310
|
const children = item.children;
|
|
15311
|
+
const description = item.description;
|
|
15312
|
+
const icon = item.icon;
|
|
15186
15313
|
return {
|
|
15187
15314
|
id: item.id || uuidGenerator$2.uuidv4(),
|
|
15188
15315
|
name: typeof name === "function" ? name : () => name,
|
|
@@ -15200,8 +15327,8 @@
|
|
|
15200
15327
|
: () => [],
|
|
15201
15328
|
isReadonlyAllowed: item.isReadonlyAllowed || false,
|
|
15202
15329
|
separator: item.separator || false,
|
|
15203
|
-
icon:
|
|
15204
|
-
description:
|
|
15330
|
+
icon: typeof icon === "function" ? icon : () => icon || "",
|
|
15331
|
+
description: typeof description === "function" ? description : () => description || "",
|
|
15205
15332
|
textColor: item.textColor,
|
|
15206
15333
|
sequence: item.sequence || 0,
|
|
15207
15334
|
};
|
|
@@ -16667,7 +16794,7 @@
|
|
|
16667
16794
|
function convertDateFormatForMoment(format) {
|
|
16668
16795
|
format = format.replace(/y/g, "Y");
|
|
16669
16796
|
format = format.replace(/d/g, "D");
|
|
16670
|
-
// "m" before "h"
|
|
16797
|
+
// "m" before "h" === month, "m" after "h" === minute
|
|
16671
16798
|
const indexH = format.indexOf("h");
|
|
16672
16799
|
if (indexH >= 0) {
|
|
16673
16800
|
format = format.slice(0, indexH).replace(/m/g, "M") + format.slice(indexH);
|
|
@@ -17521,6 +17648,7 @@
|
|
|
17521
17648
|
env.model.dispatch("SELECT_FIGURE", { id: figureId });
|
|
17522
17649
|
env.openSidePanel("ChartPanel");
|
|
17523
17650
|
},
|
|
17651
|
+
icon: "o-spreadsheet-Icon.EDIT",
|
|
17524
17652
|
},
|
|
17525
17653
|
getCopyMenuItem(figureId, env),
|
|
17526
17654
|
getCutMenuItem(figureId, env),
|
|
@@ -17552,6 +17680,7 @@
|
|
|
17552
17680
|
width,
|
|
17553
17681
|
});
|
|
17554
17682
|
},
|
|
17683
|
+
icon: "o-spreadsheet-Icon.REFRESH",
|
|
17555
17684
|
},
|
|
17556
17685
|
getDeleteMenuItem(figureId, onFigureDeleted, env),
|
|
17557
17686
|
];
|
|
@@ -17568,6 +17697,7 @@
|
|
|
17568
17697
|
env.model.dispatch("COPY");
|
|
17569
17698
|
await env.clipboard.write(env.model.getters.getClipboardContent());
|
|
17570
17699
|
},
|
|
17700
|
+
icon: "o-spreadsheet-Icon.COPY",
|
|
17571
17701
|
};
|
|
17572
17702
|
}
|
|
17573
17703
|
function getCutMenuItem(figureId, env) {
|
|
@@ -17581,6 +17711,7 @@
|
|
|
17581
17711
|
env.model.dispatch("CUT");
|
|
17582
17712
|
await env.clipboard.write(env.model.getters.getClipboardContent());
|
|
17583
17713
|
},
|
|
17714
|
+
icon: "o-spreadsheet-Icon.CUT",
|
|
17584
17715
|
};
|
|
17585
17716
|
}
|
|
17586
17717
|
function getDeleteMenuItem(figureId, onFigureDeleted, env) {
|
|
@@ -17595,6 +17726,7 @@
|
|
|
17595
17726
|
});
|
|
17596
17727
|
onFigureDeleted();
|
|
17597
17728
|
},
|
|
17729
|
+
icon: "o-spreadsheet-Icon.DELETE",
|
|
17598
17730
|
};
|
|
17599
17731
|
}
|
|
17600
17732
|
|
|
@@ -18662,7 +18794,7 @@
|
|
|
18662
18794
|
};
|
|
18663
18795
|
const categorieFunctionAll = {
|
|
18664
18796
|
name: _lt("All"),
|
|
18665
|
-
children: allFunctionListMenuBuilder
|
|
18797
|
+
children: [allFunctionListMenuBuilder],
|
|
18666
18798
|
};
|
|
18667
18799
|
function allFunctionListMenuBuilder() {
|
|
18668
18800
|
const fnNames = functionRegistry.getKeys();
|
|
@@ -18994,7 +19126,10 @@
|
|
|
18994
19126
|
};
|
|
18995
19127
|
const formatNumberNumber = {
|
|
18996
19128
|
name: _lt("Number"),
|
|
18997
|
-
description:
|
|
19129
|
+
description: (env) => formatValue(1000.12, {
|
|
19130
|
+
format: "#,##0.00",
|
|
19131
|
+
locale: env.model.getters.getLocale(),
|
|
19132
|
+
}),
|
|
18998
19133
|
execute: (env) => setFormatter(env, "#,##0.00"),
|
|
18999
19134
|
isActive: (env) => isFormatSelected(env, "#,##0.00"),
|
|
19000
19135
|
};
|
|
@@ -19005,21 +19140,34 @@
|
|
|
19005
19140
|
};
|
|
19006
19141
|
const formatNumberPercent = {
|
|
19007
19142
|
name: _lt("Percent"),
|
|
19008
|
-
description:
|
|
19143
|
+
description: (env) => formatValue(0.1012, {
|
|
19144
|
+
format: "0.00%",
|
|
19145
|
+
locale: env.model.getters.getLocale(),
|
|
19146
|
+
}),
|
|
19009
19147
|
execute: FORMAT_PERCENT_ACTION,
|
|
19010
19148
|
isActive: (env) => isFormatSelected(env, "0.00%"),
|
|
19011
19149
|
};
|
|
19012
19150
|
const formatNumberCurrency = {
|
|
19013
19151
|
name: _lt("Currency"),
|
|
19014
|
-
description:
|
|
19015
|
-
|
|
19016
|
-
|
|
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),
|
|
19017
19158
|
};
|
|
19018
19159
|
const formatNumberCurrencyRounded = {
|
|
19019
19160
|
name: _lt("Currency rounded"),
|
|
19020
|
-
description:
|
|
19021
|
-
|
|
19022
|
-
|
|
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
|
+
},
|
|
19023
19171
|
};
|
|
19024
19172
|
const formatCustomCurrency = {
|
|
19025
19173
|
name: _lt("Custom currency"),
|
|
@@ -19028,19 +19176,37 @@
|
|
|
19028
19176
|
};
|
|
19029
19177
|
const formatNumberDate = {
|
|
19030
19178
|
name: _lt("Date"),
|
|
19031
|
-
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
|
+
},
|
|
19032
19186
|
execute: (env) => setFormatter(env, env.model.getters.getLocale().dateFormat),
|
|
19033
19187
|
isActive: (env) => isFormatSelected(env, env.model.getters.getLocale().dateFormat),
|
|
19034
19188
|
};
|
|
19035
19189
|
const formatNumberTime = {
|
|
19036
19190
|
name: _lt("Time"),
|
|
19037
|
-
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
|
+
},
|
|
19038
19198
|
execute: (env) => setFormatter(env, env.model.getters.getLocale().timeFormat),
|
|
19039
19199
|
isActive: (env) => isFormatSelected(env, env.model.getters.getLocale().timeFormat),
|
|
19040
19200
|
};
|
|
19041
19201
|
const formatNumberDateTime = {
|
|
19042
19202
|
name: _lt("Date time"),
|
|
19043
|
-
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
|
+
},
|
|
19044
19210
|
execute: (env) => {
|
|
19045
19211
|
const locale = env.model.getters.getLocale();
|
|
19046
19212
|
setFormatter(env, locale.dateFormat + " " + locale.timeFormat);
|
|
@@ -19112,7 +19278,7 @@
|
|
|
19112
19278
|
};
|
|
19113
19279
|
const formatAlignmentHorizontal = {
|
|
19114
19280
|
name: _lt("Horizontal align"),
|
|
19115
|
-
icon:
|
|
19281
|
+
icon: (env) => getHorizontalAlignmentIcon(env),
|
|
19116
19282
|
};
|
|
19117
19283
|
const formatAlignmentLeft = {
|
|
19118
19284
|
name: _lt("Left"),
|
|
@@ -19137,46 +19303,50 @@
|
|
|
19137
19303
|
};
|
|
19138
19304
|
const formatAlignmentVertical = {
|
|
19139
19305
|
name: _lt("Vertical align"),
|
|
19140
|
-
icon:
|
|
19306
|
+
icon: (env) => getVerticalAlignmentIcon(env),
|
|
19141
19307
|
};
|
|
19142
19308
|
const formatAlignmentTop = {
|
|
19143
19309
|
name: _lt("Top"),
|
|
19144
19310
|
execute: (env) => setStyle(env, { verticalAlign: "top" }),
|
|
19145
|
-
isActive: (env) => (env
|
|
19311
|
+
isActive: (env) => getVerticalAlign(env) === "top",
|
|
19146
19312
|
icon: "o-spreadsheet-Icon.ALIGN_TOP",
|
|
19147
19313
|
};
|
|
19148
19314
|
const formatAlignmentMiddle = {
|
|
19149
19315
|
name: _lt("Middle"),
|
|
19150
19316
|
execute: (env) => setStyle(env, { verticalAlign: "middle" }),
|
|
19151
|
-
isActive: (env) => (env
|
|
19317
|
+
isActive: (env) => getVerticalAlign(env) === "middle",
|
|
19152
19318
|
icon: "o-spreadsheet-Icon.ALIGN_MIDDLE",
|
|
19153
19319
|
};
|
|
19154
19320
|
const formatAlignmentBottom = {
|
|
19155
19321
|
name: _lt("Bottom"),
|
|
19156
19322
|
execute: (env) => setStyle(env, { verticalAlign: "bottom" }),
|
|
19157
|
-
isActive: (env) => (env
|
|
19323
|
+
isActive: (env) => getVerticalAlign(env) === "bottom",
|
|
19158
19324
|
icon: "o-spreadsheet-Icon.ALIGN_BOTTOM",
|
|
19159
19325
|
};
|
|
19160
|
-
const
|
|
19326
|
+
const formatWrappingIcon = {
|
|
19161
19327
|
name: _lt("Wrapping"),
|
|
19162
19328
|
icon: "o-spreadsheet-Icon.WRAPPING_OVERFLOW",
|
|
19163
19329
|
};
|
|
19330
|
+
const formatWrapping = {
|
|
19331
|
+
name: _lt("Wrapping"),
|
|
19332
|
+
icon: (env) => getWrapModeIcon(env),
|
|
19333
|
+
};
|
|
19164
19334
|
const formatWrappingOverflow = {
|
|
19165
19335
|
name: _lt("Overflow"),
|
|
19166
19336
|
execute: (env) => setStyle(env, { wrapping: "overflow" }),
|
|
19167
|
-
isActive: (env) => (env
|
|
19337
|
+
isActive: (env) => getWrappingMode(env) === "overflow",
|
|
19168
19338
|
icon: "o-spreadsheet-Icon.WRAPPING_OVERFLOW",
|
|
19169
19339
|
};
|
|
19170
19340
|
const formatWrappingWrap = {
|
|
19171
19341
|
name: _lt("Wrap"),
|
|
19172
19342
|
execute: (env) => setStyle(env, { wrapping: "wrap" }),
|
|
19173
|
-
isActive: (env) => env
|
|
19343
|
+
isActive: (env) => getWrappingMode(env) === "wrap",
|
|
19174
19344
|
icon: "o-spreadsheet-Icon.WRAPPING_WRAP",
|
|
19175
19345
|
};
|
|
19176
19346
|
const formatWrappingClip = {
|
|
19177
19347
|
name: _lt("Clip"),
|
|
19178
19348
|
execute: (env) => setStyle(env, { wrapping: "clip" }),
|
|
19179
|
-
isActive: (env) => env
|
|
19349
|
+
isActive: (env) => getWrappingMode(env) === "clip",
|
|
19180
19350
|
icon: "o-spreadsheet-Icon.WRAPPING_CLIP",
|
|
19181
19351
|
};
|
|
19182
19352
|
const textColor = {
|
|
@@ -19192,14 +19362,6 @@
|
|
|
19192
19362
|
execute: OPEN_CF_SIDEPANEL_ACTION,
|
|
19193
19363
|
icon: "o-spreadsheet-Icon.CONDITIONAL_FORMAT",
|
|
19194
19364
|
};
|
|
19195
|
-
const paintFormat = {
|
|
19196
|
-
name: _lt("Paint Format"),
|
|
19197
|
-
execute: (env) => env.model.dispatch("ACTIVATE_PAINT_FORMAT", {
|
|
19198
|
-
target: env.model.getters.getSelectedZones(),
|
|
19199
|
-
}),
|
|
19200
|
-
icon: "o-spreadsheet-Icon.PAINT_FORMAT",
|
|
19201
|
-
isActive: (env) => env.model.getters.isPaintingFormat(),
|
|
19202
|
-
};
|
|
19203
19365
|
const clearFormat = {
|
|
19204
19366
|
name: _lt("Clear formatting"),
|
|
19205
19367
|
description: "Ctrl+<",
|
|
@@ -19239,6 +19401,53 @@
|
|
|
19239
19401
|
}
|
|
19240
19402
|
const cell = env.model.getters.getActiveCell();
|
|
19241
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
|
+
}
|
|
19242
19451
|
}
|
|
19243
19452
|
|
|
19244
19453
|
var ACTION_FORMAT = /*#__PURE__*/Object.freeze({
|
|
@@ -19270,6 +19479,7 @@
|
|
|
19270
19479
|
formatAlignmentTop: formatAlignmentTop,
|
|
19271
19480
|
formatAlignmentMiddle: formatAlignmentMiddle,
|
|
19272
19481
|
formatAlignmentBottom: formatAlignmentBottom,
|
|
19482
|
+
formatWrappingIcon: formatWrappingIcon,
|
|
19273
19483
|
formatWrapping: formatWrapping,
|
|
19274
19484
|
formatWrappingOverflow: formatWrappingOverflow,
|
|
19275
19485
|
formatWrappingWrap: formatWrappingWrap,
|
|
@@ -19277,7 +19487,6 @@
|
|
|
19277
19487
|
textColor: textColor,
|
|
19278
19488
|
fillColor: fillColor,
|
|
19279
19489
|
formatCF: formatCF,
|
|
19280
|
-
paintFormat: paintFormat,
|
|
19281
19490
|
clearFormat: clearFormat
|
|
19282
19491
|
});
|
|
19283
19492
|
|
|
@@ -20040,7 +20249,7 @@
|
|
|
20040
20249
|
separator: true,
|
|
20041
20250
|
})
|
|
20042
20251
|
.addChild("format_wrapping", ["format"], {
|
|
20043
|
-
...
|
|
20252
|
+
...formatWrappingIcon,
|
|
20044
20253
|
sequence: 80,
|
|
20045
20254
|
separator: true,
|
|
20046
20255
|
})
|
|
@@ -22330,17 +22539,45 @@
|
|
|
22330
22539
|
}
|
|
22331
22540
|
get formatProposals() {
|
|
22332
22541
|
const currency = this.availableCurrencies[this.state.selectedCurrencyIndex];
|
|
22333
|
-
const
|
|
22334
|
-
const
|
|
22335
|
-
const secondPosition = currency.position === "before" ? "after" : "before";
|
|
22542
|
+
const position = currency.position;
|
|
22543
|
+
const opposite = currency.position === "before" ? "after" : "before";
|
|
22336
22544
|
const symbol = this.state.currencySymbol.trim() ? this.state.currencySymbol : "";
|
|
22337
22545
|
const code = this.state.currencyCode.trim() ? this.state.currencyCode : "";
|
|
22338
|
-
|
|
22339
|
-
|
|
22340
|
-
|
|
22341
|
-
|
|
22342
|
-
|
|
22343
|
-
|
|
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
|
+
}));
|
|
22344
22581
|
}
|
|
22345
22582
|
get isSameFormat() {
|
|
22346
22583
|
const selectedFormat = this.formatProposals[this.state.selectedFormatIndex];
|
|
@@ -22397,41 +22634,6 @@
|
|
|
22397
22634
|
initAvailableCurrencies() {
|
|
22398
22635
|
this.state.selectedCurrencyIndex = 0;
|
|
22399
22636
|
}
|
|
22400
|
-
initProposalBases(decimalPlaces) {
|
|
22401
|
-
const result = [{ format: "#,##0", example: "1,000" }];
|
|
22402
|
-
const decimalRepresentation = decimalPlaces ? "." + "0".repeat(decimalPlaces) : "";
|
|
22403
|
-
if (decimalRepresentation) {
|
|
22404
|
-
result.push({
|
|
22405
|
-
format: "#,##0" + decimalRepresentation,
|
|
22406
|
-
example: "1,000" + decimalRepresentation,
|
|
22407
|
-
});
|
|
22408
|
-
}
|
|
22409
|
-
return result;
|
|
22410
|
-
}
|
|
22411
|
-
createFormatProposals(proposalBases, symbol, code, position) {
|
|
22412
|
-
let formatProposals = [];
|
|
22413
|
-
// 1 - add proposal with symbol and without code
|
|
22414
|
-
if (symbol) {
|
|
22415
|
-
for (let base of proposalBases) {
|
|
22416
|
-
formatProposals.push(this.createFormatProposal(position, base.example, base.format, symbol));
|
|
22417
|
-
}
|
|
22418
|
-
}
|
|
22419
|
-
// 2 - if code exist --> add more proposal with symbol and with code
|
|
22420
|
-
if (code) {
|
|
22421
|
-
for (let base of proposalBases) {
|
|
22422
|
-
const expression = (position === "after" ? " " : "") + code + " " + symbol;
|
|
22423
|
-
formatProposals.push(this.createFormatProposal(position, base.example, base.format, expression));
|
|
22424
|
-
}
|
|
22425
|
-
}
|
|
22426
|
-
return formatProposals;
|
|
22427
|
-
}
|
|
22428
|
-
createFormatProposal(position, baseExample, formatBase, expression) {
|
|
22429
|
-
const formatExpression = "[$" + expression + "]";
|
|
22430
|
-
return {
|
|
22431
|
-
example: position === "before" ? expression + baseExample : baseExample + expression,
|
|
22432
|
-
format: position === "before" ? formatExpression + formatBase : formatBase + formatExpression,
|
|
22433
|
-
};
|
|
22434
|
-
}
|
|
22435
22637
|
getCommonFormat() {
|
|
22436
22638
|
const selectedZones = this.env.model.getters.getSelectedZones();
|
|
22437
22639
|
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
@@ -22488,6 +22690,7 @@
|
|
|
22488
22690
|
state = owl.useState(this.initialState());
|
|
22489
22691
|
debounceTimeoutId;
|
|
22490
22692
|
showFormulaState = false;
|
|
22693
|
+
debouncedUpdateSearch;
|
|
22491
22694
|
findAndReplaceRef = owl.useRef("findAndReplace");
|
|
22492
22695
|
get hasSearchResult() {
|
|
22493
22696
|
return this.env.model.getters.getCurrentSelectedMatchIndex() !== null;
|
|
@@ -22497,11 +22700,16 @@
|
|
|
22497
22700
|
}
|
|
22498
22701
|
setup() {
|
|
22499
22702
|
this.showFormulaState = this.env.model.getters.shouldShowFormulas();
|
|
22703
|
+
this.debouncedUpdateSearch = debounce(this.updateSearch.bind(this), 200);
|
|
22500
22704
|
owl.onMounted(() => this.focusInput());
|
|
22501
22705
|
owl.onWillUnmount(() => {
|
|
22502
22706
|
this.env.model.dispatch("CLEAR_SEARCH");
|
|
22503
22707
|
this.env.model.dispatch("SET_FORMULA_VISIBILITY", { show: this.showFormulaState });
|
|
22504
22708
|
});
|
|
22709
|
+
owl.useEffect(() => {
|
|
22710
|
+
this.state.searchOptions.searchFormulas = this.env.model.getters.shouldShowFormulas();
|
|
22711
|
+
this.searchFormulas();
|
|
22712
|
+
}, () => [this.env.model.getters.shouldShowFormulas()]);
|
|
22505
22713
|
}
|
|
22506
22714
|
onInput(ev) {
|
|
22507
22715
|
this.state.toSearch = ev.target.value;
|
|
@@ -22521,10 +22729,6 @@
|
|
|
22521
22729
|
this.replace();
|
|
22522
22730
|
}
|
|
22523
22731
|
}
|
|
22524
|
-
onFocusSidePanel() {
|
|
22525
|
-
this.state.searchOptions.searchFormulas = this.env.model.getters.shouldShowFormulas();
|
|
22526
|
-
this.env.model.dispatch("REFRESH_SEARCH");
|
|
22527
|
-
}
|
|
22528
22732
|
searchFormulas() {
|
|
22529
22733
|
this.env.model.dispatch("SET_FORMULA_VISIBILITY", {
|
|
22530
22734
|
show: this.state.searchOptions.searchFormulas,
|
|
@@ -22543,13 +22747,6 @@
|
|
|
22543
22747
|
searchOptions: this.state.searchOptions,
|
|
22544
22748
|
});
|
|
22545
22749
|
}
|
|
22546
|
-
debouncedUpdateSearch() {
|
|
22547
|
-
clearTimeout(this.debounceTimeoutId);
|
|
22548
|
-
this.debounceTimeoutId = setTimeout(() => {
|
|
22549
|
-
this.updateSearch();
|
|
22550
|
-
this.debounceTimeoutId = undefined;
|
|
22551
|
-
}, 400);
|
|
22552
|
-
}
|
|
22553
22750
|
replace() {
|
|
22554
22751
|
this.env.model.dispatch("REPLACE_SEARCH", {
|
|
22555
22752
|
replaceWith: this.state.replaceWith,
|
|
@@ -23234,7 +23431,7 @@
|
|
|
23234
23431
|
selection.removeAllRanges();
|
|
23235
23432
|
selection.addRange(range);
|
|
23236
23433
|
}
|
|
23237
|
-
if (start
|
|
23434
|
+
if (start === end && start === 0) {
|
|
23238
23435
|
range.setStart(this.el, 0);
|
|
23239
23436
|
range.setEnd(this.el, 0);
|
|
23240
23437
|
}
|
|
@@ -23487,7 +23684,7 @@
|
|
|
23487
23684
|
}, 0);
|
|
23488
23685
|
}
|
|
23489
23686
|
}
|
|
23490
|
-
if (nodeToFind.nodeName === "P" && !isFirstParagraph && nodeToFind.textContent
|
|
23687
|
+
if (nodeToFind.nodeName === "P" && !isFirstParagraph && nodeToFind.textContent === "") {
|
|
23491
23688
|
usedCharacters++;
|
|
23492
23689
|
}
|
|
23493
23690
|
return usedCharacters;
|
|
@@ -25034,6 +25231,14 @@
|
|
|
25034
25231
|
};
|
|
25035
25232
|
}
|
|
25036
25233
|
|
|
25234
|
+
const CURSOR_SVG = /*xml*/ `
|
|
25235
|
+
<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>
|
|
25236
|
+
`;
|
|
25237
|
+
css /* scss */ `
|
|
25238
|
+
.o-paint-format-cursor {
|
|
25239
|
+
cursor: url("data:image/svg+xml,${encodeURIComponent(CURSOR_SVG)}"), auto;
|
|
25240
|
+
}
|
|
25241
|
+
`;
|
|
25037
25242
|
function useCellHovered(env, gridRef, callback) {
|
|
25038
25243
|
let hoveredPosition = {
|
|
25039
25244
|
col: undefined,
|
|
@@ -25157,6 +25362,12 @@
|
|
|
25157
25362
|
}
|
|
25158
25363
|
return this.gridOverlay.el;
|
|
25159
25364
|
}
|
|
25365
|
+
get style() {
|
|
25366
|
+
return this.props.gridOverlayDimensions;
|
|
25367
|
+
}
|
|
25368
|
+
get isPaintingFormat() {
|
|
25369
|
+
return this.env.model.getters.isPaintingFormat();
|
|
25370
|
+
}
|
|
25160
25371
|
onMouseDown(ev) {
|
|
25161
25372
|
if (ev.button > 0) {
|
|
25162
25373
|
// not main button, probably a context menu
|
|
@@ -26334,6 +26545,9 @@
|
|
|
26334
26545
|
else if (this.menuState.isOpen) {
|
|
26335
26546
|
this.closeMenu();
|
|
26336
26547
|
}
|
|
26548
|
+
else if (this.env.model.getters.isPaintingFormat()) {
|
|
26549
|
+
this.env.model.dispatch("CANCEL_PAINT_FORMAT");
|
|
26550
|
+
}
|
|
26337
26551
|
else {
|
|
26338
26552
|
this.env.model.dispatch("CLEAN_CLIPBOARD_HIGHLIGHT");
|
|
26339
26553
|
}
|
|
@@ -27536,8 +27750,8 @@
|
|
|
27536
27750
|
throw new Error("Multiple escaped blocks in format");
|
|
27537
27751
|
}
|
|
27538
27752
|
convertedFormat = convertedFormat.replace(/"(.*)"/g, "[$$$1]"); // replace '"..."' by '[$...]'
|
|
27539
|
-
convertedFormat = convertedFormat.replace(/_.{1}/g, ""); // _
|
|
27540
|
-
convertedFormat = convertedFormat.replace(/\*.{1}/g, ""); // *
|
|
27753
|
+
convertedFormat = convertedFormat.replace(/_.{1}/g, ""); // _ === ignore width of next char for align purposes. Not supported ATM
|
|
27754
|
+
convertedFormat = convertedFormat.replace(/\*.{1}/g, ""); // * === repeat next character enough to fill the line. Not supported ATM
|
|
27541
27755
|
convertedFormat = convertedFormat.replace(/\\ /g, " "); // unescape spaces
|
|
27542
27756
|
convertedFormat = convertedFormat.replace(/\\./g, (match) => match[1]); // unescape other characters
|
|
27543
27757
|
if (isXlsxDateFormat(convertedFormat)) {
|
|
@@ -28829,29 +29043,26 @@
|
|
|
28829
29043
|
return new XMLString(concat(str));
|
|
28830
29044
|
}
|
|
28831
29045
|
/**
|
|
28832
|
-
* Removes the namespace of all the xml tags in the string.
|
|
29046
|
+
* Removes the escaped namespace of all the xml tags in the string.
|
|
28833
29047
|
*
|
|
28834
|
-
* Eg. : "
|
|
29048
|
+
* Eg. : "NAMESPACEnsNAMESPACEtest a" => "test a"
|
|
28835
29049
|
*/
|
|
28836
|
-
function
|
|
28837
|
-
return
|
|
29050
|
+
function removeTagEscapedNamespaces(tag) {
|
|
29051
|
+
return tag.replace(/NAMESPACE.*NAMESPACE(.*)/, "$1");
|
|
28838
29052
|
}
|
|
28839
29053
|
/**
|
|
28840
|
-
*
|
|
29054
|
+
* Encase the namespaces in the element's tags with NAMESPACE string
|
|
28841
29055
|
*
|
|
28842
|
-
*
|
|
28843
|
-
*/
|
|
28844
|
-
function escapeNamespaces(query) {
|
|
28845
|
-
return query.replace(/([a-z0-9]+):(?=[a-z0-9]+)/gi, "$1\\:");
|
|
28846
|
-
}
|
|
28847
|
-
/**
|
|
28848
|
-
* Return true if the querySelector ignores the namespaces when searching for a tag in the DOM.
|
|
29056
|
+
* e.g. <x:foo> becomes <NAMESPACExNAMESPACEFoo>
|
|
28849
29057
|
*
|
|
28850
|
-
*
|
|
29058
|
+
* That's useful because namespaces aren't supported by the HTML specification, so it's arbitrary whether a HTML parser/querySelector
|
|
29059
|
+
* implementation will support namespaces in the tags or not.
|
|
28851
29060
|
*/
|
|
28852
|
-
function
|
|
28853
|
-
|
|
28854
|
-
|
|
29061
|
+
function escapeTagNamespaces(str) {
|
|
29062
|
+
return str.replaceAll(/(<\/?)([a-zA-Z0-9]+):([a-zA-Z0-9]+)/g, "$1" + "NAMESPACE" + "$2" + "NAMESPACE" + "$3");
|
|
29063
|
+
}
|
|
29064
|
+
function escapeQueryNameSpaces(query) {
|
|
29065
|
+
return query.replaceAll(/([a-zA-Z0-9]+):([a-zA-Z0-9]+)/g, "NAMESPACE" + "$1" + "NAMESPACE" + "$2");
|
|
28855
29066
|
}
|
|
28856
29067
|
|
|
28857
29068
|
class AttributeValue {
|
|
@@ -28881,14 +29092,20 @@
|
|
|
28881
29092
|
// The xml file we are currently parsing. We should have one Extractor class by XLSXImportFile, but
|
|
28882
29093
|
// the XLSXImportFile contains both the main .xml file, and the .rels file
|
|
28883
29094
|
currentFile = undefined;
|
|
28884
|
-
|
|
28885
|
-
|
|
29095
|
+
/**
|
|
29096
|
+
* /!\ Important : There should be no namespaces in the tags of the XML files.
|
|
29097
|
+
*
|
|
29098
|
+
* This class use native querySelector and querySelectorAll, that's used for HTML (not XML). These aren't supposed to
|
|
29099
|
+
* handled namespaces, as they are not supported by the HTML specification. Some implementations (most browsers) do
|
|
29100
|
+
* actually support namespaces, but some don't (e.g. jsdom).
|
|
29101
|
+
*
|
|
29102
|
+
* The namespace should be escaped as with NAMESPACE string (eg. <t:foo> => <NAMESPACEtNAMESPACEfoo>).
|
|
29103
|
+
*/
|
|
28886
29104
|
constructor(rootFile, xlsxStructure, warningManager) {
|
|
28887
29105
|
this.rootFile = rootFile;
|
|
28888
29106
|
this.currentFile = rootFile.file.fileName;
|
|
28889
29107
|
this.xlsxFileStructure = xlsxStructure;
|
|
28890
29108
|
this.warningManager = warningManager;
|
|
28891
|
-
this.areNamespaceIgnored = areNamespaceIgnoredByQuerySelector();
|
|
28892
29109
|
this.relationships = {};
|
|
28893
29110
|
if (rootFile.rels) {
|
|
28894
29111
|
this.extractRelationships(rootFile.rels).map((rel) => {
|
|
@@ -29114,29 +29331,13 @@
|
|
|
29114
29331
|
throw new Error("Cannot find target file");
|
|
29115
29332
|
return f;
|
|
29116
29333
|
}
|
|
29117
|
-
/**
|
|
29118
|
-
* Wrapper of querySelector, but we'll remove the namespaces from the query if areNamespacesIgnored is true.
|
|
29119
|
-
*
|
|
29120
|
-
* Why we need to do this :
|
|
29121
|
-
* - For an XML "<t:test />"
|
|
29122
|
-
* - on Jest(jsdom) : xml.querySelector("test") == null, xml.querySelector("t\\:test") == <t:test />
|
|
29123
|
-
* - on Browser : xml.querySelector("test") == <t:test />, xml.querySelector("t\\:test") == null
|
|
29124
|
-
*/
|
|
29125
29334
|
querySelector(element, query) {
|
|
29126
|
-
|
|
29127
|
-
return element.querySelector(
|
|
29335
|
+
const escapedQuery = escapeQueryNameSpaces(query);
|
|
29336
|
+
return element.querySelector(escapedQuery);
|
|
29128
29337
|
}
|
|
29129
|
-
/**
|
|
29130
|
-
* Wrapper of querySelectorAll, but we'll remove the namespaces from the query if areNamespacesIgnored is true.
|
|
29131
|
-
*
|
|
29132
|
-
* Why we need to do this :
|
|
29133
|
-
* - For an XML "<t:test />"
|
|
29134
|
-
* - on Jest(jsdom) : xml.querySelectorAll("test") == [], xml.querySelectorAll("t\\:test") == [<t:test />]
|
|
29135
|
-
* - on Browser : xml.querySelectorAll("test") == [<t:test />], xml.querySelectorAll("t\\:test") == []
|
|
29136
|
-
*/
|
|
29137
29338
|
querySelectorAll(element, query) {
|
|
29138
|
-
|
|
29139
|
-
return element.querySelectorAll(
|
|
29339
|
+
const escapedQuery = escapeQueryNameSpaces(query);
|
|
29340
|
+
return element.querySelectorAll(escapedQuery);
|
|
29140
29341
|
}
|
|
29141
29342
|
/**
|
|
29142
29343
|
* Get a color from its id in the Theme's colorScheme.
|
|
@@ -29376,7 +29577,7 @@
|
|
|
29376
29577
|
throw new Error("Missing plot area in the chart definition.");
|
|
29377
29578
|
}
|
|
29378
29579
|
for (let child of plotAreaElement.children) {
|
|
29379
|
-
const tag =
|
|
29580
|
+
const tag = removeTagEscapedNamespaces(child.tagName);
|
|
29380
29581
|
if (XLSX_CHART_TYPES.some((chartType) => chartType === tag)) {
|
|
29381
29582
|
return tag;
|
|
29382
29583
|
}
|
|
@@ -29388,7 +29589,7 @@
|
|
|
29388
29589
|
class XlsxFigureExtractor extends XlsxBaseExtractor {
|
|
29389
29590
|
extractFigures() {
|
|
29390
29591
|
return this.mapOnElements({ parent: this.rootFile.file.xml, query: "xdr:wsDr", children: true }, (figureElement) => {
|
|
29391
|
-
const anchorType =
|
|
29592
|
+
const anchorType = removeTagEscapedNamespaces(figureElement.tagName);
|
|
29392
29593
|
if (anchorType !== "twoCellAnchor") {
|
|
29393
29594
|
throw new Error("Only twoCellAnchor are supported for xlsx drawings.");
|
|
29394
29595
|
}
|
|
@@ -30022,7 +30223,8 @@
|
|
|
30022
30223
|
for (let key of Object.keys(files)) {
|
|
30023
30224
|
// Random files can be in xlsx (like a bin file for printer settings)
|
|
30024
30225
|
if (key.endsWith(".xml") || key.endsWith(".rels")) {
|
|
30025
|
-
|
|
30226
|
+
const contentString = escapeTagNamespaces(files[key]);
|
|
30227
|
+
this.xmls[key] = parseXML(new XMLString(contentString));
|
|
30026
30228
|
}
|
|
30027
30229
|
else if (key.includes("media/image")) {
|
|
30028
30230
|
this.images.push({
|
|
@@ -31089,7 +31291,7 @@
|
|
|
31089
31291
|
}
|
|
31090
31292
|
/**
|
|
31091
31293
|
* Set the borders of a cell.
|
|
31092
|
-
* It overrides the current border if override
|
|
31294
|
+
* It overrides the current border if override === true.
|
|
31093
31295
|
*/
|
|
31094
31296
|
setBorder(sheetId, col, row, border, override = true) {
|
|
31095
31297
|
if (override || !this.borders?.[sheetId]?.[col]?.[row]?.vertical) {
|
|
@@ -32359,7 +32561,9 @@
|
|
|
32359
32561
|
const numHeader = this.getters.getNumberRows(sheetId);
|
|
32360
32562
|
let gridHeight = 0;
|
|
32361
32563
|
for (let i = 0; i < numHeader; i++) {
|
|
32362
|
-
|
|
32564
|
+
// TODO : since the row size is an UI value now, this doesn't work anymore. Using the default cell height is
|
|
32565
|
+
// a temporary solution at best, but is broken.
|
|
32566
|
+
gridHeight += this.getters.getUserRowSize(sheetId, i) || DEFAULT_CELL_HEIGHT;
|
|
32363
32567
|
}
|
|
32364
32568
|
const figures = this.getters.getFigures(sheetId);
|
|
32365
32569
|
for (const figure of figures) {
|
|
@@ -32785,33 +32989,15 @@
|
|
|
32785
32989
|
}
|
|
32786
32990
|
|
|
32787
32991
|
class HeaderSizePlugin extends CorePlugin {
|
|
32788
|
-
static getters = ["
|
|
32992
|
+
static getters = ["getUserRowSize", "getColSize"];
|
|
32789
32993
|
sizes = {};
|
|
32790
32994
|
handle(cmd) {
|
|
32791
32995
|
switch (cmd.type) {
|
|
32792
32996
|
case "CREATE_SHEET": {
|
|
32793
|
-
|
|
32794
|
-
const sizes = {
|
|
32795
|
-
COL: computedSizes.COL.map((size) => ({
|
|
32796
|
-
manualSize: undefined,
|
|
32797
|
-
computedSize: lazy(size),
|
|
32798
|
-
})),
|
|
32799
|
-
ROW: computedSizes.ROW.map((size) => ({
|
|
32800
|
-
manualSize: undefined,
|
|
32801
|
-
computedSize: lazy(size),
|
|
32802
|
-
})),
|
|
32803
|
-
};
|
|
32804
|
-
this.history.update("sizes", cmd.sheetId, sizes);
|
|
32997
|
+
this.history.update("sizes", cmd.sheetId, { COL: [], ROW: [] });
|
|
32805
32998
|
break;
|
|
32806
32999
|
}
|
|
32807
33000
|
case "DUPLICATE_SHEET":
|
|
32808
|
-
// make sure the values are computed in case the original sheet is deleted
|
|
32809
|
-
for (const row of this.sizes[cmd.sheetId].ROW) {
|
|
32810
|
-
row.computedSize();
|
|
32811
|
-
}
|
|
32812
|
-
for (const col of this.sizes[cmd.sheetId].COL) {
|
|
32813
|
-
col.computedSize();
|
|
32814
|
-
}
|
|
32815
33001
|
this.history.update("sizes", cmd.sheetIdTo, deepCopy(this.sizes[cmd.sheetId]));
|
|
32816
33002
|
break;
|
|
32817
33003
|
case "DELETE_SHEET":
|
|
@@ -32820,21 +33006,8 @@
|
|
|
32820
33006
|
this.history.update("sizes", sizes);
|
|
32821
33007
|
break;
|
|
32822
33008
|
case "REMOVE_COLUMNS_ROWS": {
|
|
32823
|
-
|
|
32824
|
-
|
|
32825
|
-
sizes.splice(headerIndex, 1);
|
|
32826
|
-
}
|
|
32827
|
-
const min = Math.min(...cmd.elements);
|
|
32828
|
-
sizes = sizes.map((size, row) => {
|
|
32829
|
-
if (cmd.dimension === "ROW" && row >= min) {
|
|
32830
|
-
// invalidate sizes
|
|
32831
|
-
return {
|
|
32832
|
-
manualSize: size.manualSize,
|
|
32833
|
-
computedSize: lazy(() => this.getRowTallestCellSize(cmd.sheetId, row)),
|
|
32834
|
-
};
|
|
32835
|
-
}
|
|
32836
|
-
return size;
|
|
32837
|
-
});
|
|
33009
|
+
const arr = this.sizes[cmd.sheetId][cmd.dimension];
|
|
33010
|
+
const sizes = removeIndexesFromArray(arr, cmd.elements);
|
|
32838
33011
|
this.history.update("sizes", cmd.sheetId, cmd.dimension, sizes);
|
|
32839
33012
|
break;
|
|
32840
33013
|
}
|
|
@@ -32843,51 +33016,18 @@
|
|
|
32843
33016
|
const addIndex = getAddHeaderStartIndex(cmd.position, cmd.base);
|
|
32844
33017
|
const baseSize = sizes[cmd.base];
|
|
32845
33018
|
sizes.splice(addIndex, 0, ...Array(cmd.quantity).fill(baseSize));
|
|
32846
|
-
sizes = sizes.map((size, row) => {
|
|
32847
|
-
if (cmd.dimension === "ROW" && row > cmd.base + cmd.quantity) {
|
|
32848
|
-
// invalidate sizes
|
|
32849
|
-
return {
|
|
32850
|
-
manualSize: size.manualSize,
|
|
32851
|
-
computedSize: lazy(() => this.getRowTallestCellSize(cmd.sheetId, row)),
|
|
32852
|
-
};
|
|
32853
|
-
}
|
|
32854
|
-
return size;
|
|
32855
|
-
});
|
|
32856
33019
|
this.history.update("sizes", cmd.sheetId, cmd.dimension, sizes);
|
|
32857
33020
|
break;
|
|
32858
33021
|
}
|
|
32859
33022
|
case "RESIZE_COLUMNS_ROWS":
|
|
32860
|
-
|
|
32861
|
-
|
|
32862
|
-
|
|
32863
|
-
const size = height;
|
|
32864
|
-
this.history.update("sizes", cmd.sheetId, cmd.dimension, el, {
|
|
32865
|
-
manualSize: cmd.size || undefined,
|
|
32866
|
-
computedSize: lazy(size),
|
|
32867
|
-
});
|
|
32868
|
-
}
|
|
32869
|
-
else {
|
|
32870
|
-
this.history.update("sizes", cmd.sheetId, cmd.dimension, el, {
|
|
32871
|
-
manualSize: cmd.size || undefined,
|
|
32872
|
-
computedSize: lazy(cmd.size || DEFAULT_CELL_WIDTH),
|
|
32873
|
-
});
|
|
33023
|
+
if (cmd.dimension === "ROW") {
|
|
33024
|
+
for (const el of cmd.elements) {
|
|
33025
|
+
this.history.update("sizes", cmd.sheetId, cmd.dimension, el, cmd.size || undefined);
|
|
32874
33026
|
}
|
|
32875
33027
|
}
|
|
32876
|
-
|
|
32877
|
-
|
|
32878
|
-
|
|
32879
|
-
const { sheetId, row } = cmd;
|
|
32880
|
-
this.history.update("sizes", sheetId, "ROW", row, "computedSize", lazy(() => this.getRowTallestCellSize(sheetId, row)));
|
|
32881
|
-
}
|
|
32882
|
-
break;
|
|
32883
|
-
case "ADD_MERGE":
|
|
32884
|
-
case "REMOVE_MERGE":
|
|
32885
|
-
for (let target of cmd.target) {
|
|
32886
|
-
for (let row of range(target.top, target.bottom + 1)) {
|
|
32887
|
-
const rowHeight = this.getRowTallestCellSize(cmd.sheetId, row);
|
|
32888
|
-
if (rowHeight !== this.getRowSize(cmd.sheetId, row)) {
|
|
32889
|
-
this.history.update("sizes", cmd.sheetId, "ROW", row, "computedSize", lazy(rowHeight));
|
|
32890
|
-
}
|
|
33028
|
+
else {
|
|
33029
|
+
for (const el of cmd.elements) {
|
|
33030
|
+
this.history.update("sizes", cmd.sheetId, cmd.dimension, el, cmd.size || undefined);
|
|
32891
33031
|
}
|
|
32892
33032
|
}
|
|
32893
33033
|
break;
|
|
@@ -32895,94 +33035,29 @@
|
|
|
32895
33035
|
return;
|
|
32896
33036
|
}
|
|
32897
33037
|
getColSize(sheetId, index) {
|
|
32898
|
-
return this.
|
|
32899
|
-
}
|
|
32900
|
-
getRowSize(sheetId, index) {
|
|
32901
|
-
return this.getHeaderSize(sheetId, "ROW", index);
|
|
32902
|
-
}
|
|
32903
|
-
getHeaderSize(sheetId, dimension, index) {
|
|
32904
|
-
return Math.round(this.sizes[sheetId]?.[dimension][index]?.manualSize ||
|
|
32905
|
-
this.sizes[sheetId]?.[dimension][index]?.computedSize() ||
|
|
32906
|
-
this.getDefaultHeaderSize(dimension));
|
|
32907
|
-
}
|
|
32908
|
-
computeSheetSizes(sheetId) {
|
|
32909
|
-
const sizes = { COL: [], ROW: [] };
|
|
32910
|
-
for (let col of range(0, this.getters.getNumberCols(sheetId))) {
|
|
32911
|
-
sizes.COL.push(this.getHeaderSize(sheetId, "COL", col));
|
|
32912
|
-
}
|
|
32913
|
-
for (let row of range(0, this.getters.getNumberRows(sheetId))) {
|
|
32914
|
-
let rowSize = this.sizes[sheetId]?.["ROW"]?.[row].manualSize;
|
|
32915
|
-
if (!rowSize) {
|
|
32916
|
-
const height = this.getRowTallestCellSize(sheetId, row);
|
|
32917
|
-
rowSize = height;
|
|
32918
|
-
}
|
|
32919
|
-
sizes.ROW.push(rowSize);
|
|
32920
|
-
}
|
|
32921
|
-
return sizes;
|
|
33038
|
+
return Math.round(this.sizes[sheetId]?.["COL"][index] || DEFAULT_CELL_WIDTH);
|
|
32922
33039
|
}
|
|
32923
|
-
|
|
32924
|
-
|
|
32925
|
-
|
|
32926
|
-
/**
|
|
32927
|
-
* Return the height the cell should have in the sheet, which is either DEFAULT_CELL_HEIGHT if the cell is in a multi-row
|
|
32928
|
-
* merge, or the height of the cell computed based on its font size.
|
|
32929
|
-
*/
|
|
32930
|
-
getCellHeight(position) {
|
|
32931
|
-
const merge = this.getters.getMerge(position);
|
|
32932
|
-
if (merge && merge.bottom !== merge.top) {
|
|
32933
|
-
return DEFAULT_CELL_HEIGHT;
|
|
32934
|
-
}
|
|
32935
|
-
const cell = this.getters.getCell(position);
|
|
32936
|
-
return getDefaultCellHeight(cell);
|
|
32937
|
-
}
|
|
32938
|
-
/**
|
|
32939
|
-
* Get the tallest cell of a row and its size.
|
|
32940
|
-
*
|
|
32941
|
-
* The tallest cell of the row correspond to the cell with the biggest font size,
|
|
32942
|
-
* and that is not part of a multi-line merge.
|
|
32943
|
-
*/
|
|
32944
|
-
getRowTallestCellSize(sheetId, row) {
|
|
32945
|
-
const cellIds = this.getters.getRowCells(sheetId, row);
|
|
32946
|
-
let maxHeight = 0;
|
|
32947
|
-
for (let i = 0; i < cellIds.length; i++) {
|
|
32948
|
-
const cell = this.getters.getCellById(cellIds[i]);
|
|
32949
|
-
if (!cell)
|
|
32950
|
-
continue;
|
|
32951
|
-
const position = this.getters.getCellPosition(cell.id);
|
|
32952
|
-
const cellHeight = this.getCellHeight(position);
|
|
32953
|
-
if (cellHeight > maxHeight && cellHeight > DEFAULT_CELL_HEIGHT) {
|
|
32954
|
-
maxHeight = cellHeight;
|
|
32955
|
-
}
|
|
32956
|
-
}
|
|
32957
|
-
if (maxHeight <= DEFAULT_CELL_HEIGHT) {
|
|
32958
|
-
return DEFAULT_CELL_HEIGHT;
|
|
32959
|
-
}
|
|
32960
|
-
return maxHeight;
|
|
33040
|
+
getUserRowSize(sheetId, index) {
|
|
33041
|
+
const rowSize = this.sizes[sheetId]?.["ROW"][index];
|
|
33042
|
+
return rowSize ? Math.round(rowSize) : undefined;
|
|
32961
33043
|
}
|
|
32962
33044
|
import(data) {
|
|
32963
33045
|
for (let sheet of data.sheets) {
|
|
32964
|
-
const
|
|
33046
|
+
const sizes = {
|
|
33047
|
+
COL: Array(sheet.colNumber).fill(undefined),
|
|
33048
|
+
ROW: Array(sheet.rowNumber).fill(undefined),
|
|
33049
|
+
};
|
|
32965
33050
|
for (let [rowIndex, row] of Object.entries(sheet.rows)) {
|
|
32966
33051
|
if (row.size) {
|
|
32967
|
-
|
|
33052
|
+
sizes["ROW"][rowIndex] = row.size;
|
|
32968
33053
|
}
|
|
32969
33054
|
}
|
|
32970
33055
|
for (let [colIndex, col] of Object.entries(sheet.cols)) {
|
|
32971
33056
|
if (col.size) {
|
|
32972
|
-
|
|
32973
|
-
}
|
|
32974
|
-
}
|
|
32975
|
-
|
|
32976
|
-
this.sizes[sheet.id] = {
|
|
32977
|
-
COL: computedSizes.COL.map((size, i) => ({
|
|
32978
|
-
manualSize: manualSizes.COL[i],
|
|
32979
|
-
computedSize: lazy(size),
|
|
32980
|
-
})),
|
|
32981
|
-
ROW: computedSizes.ROW.map((size, i) => ({
|
|
32982
|
-
manualSize: manualSizes.ROW[i],
|
|
32983
|
-
computedSize: lazy(size),
|
|
32984
|
-
})),
|
|
32985
|
-
};
|
|
33057
|
+
sizes["COL"][colIndex] = col.size;
|
|
33058
|
+
}
|
|
33059
|
+
}
|
|
33060
|
+
this.sizes[sheet.id] = sizes;
|
|
32986
33061
|
}
|
|
32987
33062
|
return;
|
|
32988
33063
|
}
|
|
@@ -33003,9 +33078,12 @@
|
|
|
33003
33078
|
if (sheet.rows === undefined) {
|
|
33004
33079
|
sheet.rows = {};
|
|
33005
33080
|
}
|
|
33006
|
-
for (
|
|
33007
|
-
if (exportDefaults || this.sizes[sheet.id]["ROW"][row]
|
|
33008
|
-
sheet.rows[row] = {
|
|
33081
|
+
for (const row of range(0, this.getters.getNumberRows(sheet.id))) {
|
|
33082
|
+
if (exportDefaults || this.sizes[sheet.id]["ROW"][row]) {
|
|
33083
|
+
sheet.rows[row] = {
|
|
33084
|
+
...sheet.rows[row],
|
|
33085
|
+
size: this.getUserRowSize(sheet.id, row) ?? DEFAULT_CELL_HEIGHT,
|
|
33086
|
+
};
|
|
33009
33087
|
}
|
|
33010
33088
|
}
|
|
33011
33089
|
// Export col sizes
|
|
@@ -33013,7 +33091,7 @@
|
|
|
33013
33091
|
sheet.cols = {};
|
|
33014
33092
|
}
|
|
33015
33093
|
for (let col of range(0, this.getters.getNumberCols(sheet.id))) {
|
|
33016
|
-
if (exportDefaults || this.sizes[sheet.id]["COL"][col]
|
|
33094
|
+
if (exportDefaults || this.sizes[sheet.id]["COL"][col]) {
|
|
33017
33095
|
sheet.cols[col] = { ...sheet.cols[col], size: this.getColSize(sheet.id, col) };
|
|
33018
33096
|
}
|
|
33019
33097
|
}
|
|
@@ -36569,7 +36647,7 @@
|
|
|
36569
36647
|
case "ContainsText":
|
|
36570
36648
|
return cell.value.toString().indexOf(values[0].toString()) > -1;
|
|
36571
36649
|
case "NotContains":
|
|
36572
|
-
return !cell.value || cell.value.toString().indexOf(values[0].toString())
|
|
36650
|
+
return !cell.value || cell.value.toString().indexOf(values[0].toString()) === -1;
|
|
36573
36651
|
case "GreaterThan":
|
|
36574
36652
|
return cell.value > values[0];
|
|
36575
36653
|
case "GreaterThanOrEqual":
|
|
@@ -36596,6 +36674,156 @@
|
|
|
36596
36674
|
};
|
|
36597
36675
|
}
|
|
36598
36676
|
|
|
36677
|
+
class UIRowSizePlugin extends UIPlugin {
|
|
36678
|
+
static getters = ["getRowSize"];
|
|
36679
|
+
tallestCellInRow = {};
|
|
36680
|
+
ctx = document.createElement("canvas").getContext("2d");
|
|
36681
|
+
handle(cmd) {
|
|
36682
|
+
switch (cmd.type) {
|
|
36683
|
+
case "START":
|
|
36684
|
+
for (const sheetId of this.getters.getSheetIds()) {
|
|
36685
|
+
this.initializeSheet(sheetId);
|
|
36686
|
+
}
|
|
36687
|
+
break;
|
|
36688
|
+
case "CREATE_SHEET": {
|
|
36689
|
+
this.initializeSheet(cmd.sheetId);
|
|
36690
|
+
break;
|
|
36691
|
+
}
|
|
36692
|
+
case "DUPLICATE_SHEET": {
|
|
36693
|
+
const tallestCells = deepCopy(this.tallestCellInRow[cmd.sheetId]);
|
|
36694
|
+
this.history.update("tallestCellInRow", cmd.sheetIdTo, tallestCells);
|
|
36695
|
+
break;
|
|
36696
|
+
}
|
|
36697
|
+
case "DELETE_SHEET":
|
|
36698
|
+
const tallestCells = { ...this.tallestCellInRow };
|
|
36699
|
+
delete tallestCells[cmd.sheetId];
|
|
36700
|
+
this.history.update("tallestCellInRow", tallestCells);
|
|
36701
|
+
break;
|
|
36702
|
+
case "REMOVE_COLUMNS_ROWS": {
|
|
36703
|
+
if (cmd.dimension === "COL") {
|
|
36704
|
+
return;
|
|
36705
|
+
}
|
|
36706
|
+
const tallestCells = removeIndexesFromArray(this.tallestCellInRow[cmd.sheetId], cmd.elements);
|
|
36707
|
+
this.history.update("tallestCellInRow", cmd.sheetId, tallestCells);
|
|
36708
|
+
break;
|
|
36709
|
+
}
|
|
36710
|
+
case "ADD_COLUMNS_ROWS": {
|
|
36711
|
+
if (cmd.dimension === "COL") {
|
|
36712
|
+
return;
|
|
36713
|
+
}
|
|
36714
|
+
const addIndex = getAddHeaderStartIndex(cmd.position, cmd.base);
|
|
36715
|
+
const newCells = Array(cmd.quantity).fill(undefined);
|
|
36716
|
+
const newTallestCells = insertItemsAtIndex(this.tallestCellInRow[cmd.sheetId], newCells, addIndex);
|
|
36717
|
+
this.history.update("tallestCellInRow", cmd.sheetId, newTallestCells);
|
|
36718
|
+
break;
|
|
36719
|
+
}
|
|
36720
|
+
case "RESIZE_COLUMNS_ROWS":
|
|
36721
|
+
{
|
|
36722
|
+
const sheetId = cmd.sheetId;
|
|
36723
|
+
if (cmd.dimension === "ROW") {
|
|
36724
|
+
for (const row of cmd.elements) {
|
|
36725
|
+
const tallestCell = this.getRowTallestCell(sheetId, row);
|
|
36726
|
+
this.history.update("tallestCellInRow", sheetId, row, tallestCell);
|
|
36727
|
+
}
|
|
36728
|
+
}
|
|
36729
|
+
else {
|
|
36730
|
+
// Recompute row heights on col size change, they might have changed because of wrapped text
|
|
36731
|
+
for (const row of range(0, this.getters.getNumberRows(sheetId))) {
|
|
36732
|
+
for (const col of cmd.elements) {
|
|
36733
|
+
this.updateRowSizeForCellChange(sheetId, row, col);
|
|
36734
|
+
}
|
|
36735
|
+
}
|
|
36736
|
+
}
|
|
36737
|
+
}
|
|
36738
|
+
break;
|
|
36739
|
+
case "UPDATE_CELL":
|
|
36740
|
+
this.updateRowSizeForCellChange(cmd.sheetId, cmd.row, cmd.col);
|
|
36741
|
+
break;
|
|
36742
|
+
case "ADD_MERGE":
|
|
36743
|
+
case "REMOVE_MERGE":
|
|
36744
|
+
for (const target of cmd.target) {
|
|
36745
|
+
for (const position of positions(target)) {
|
|
36746
|
+
this.updateRowSizeForCellChange(cmd.sheetId, position.row, position.col);
|
|
36747
|
+
}
|
|
36748
|
+
}
|
|
36749
|
+
}
|
|
36750
|
+
return;
|
|
36751
|
+
}
|
|
36752
|
+
getRowSize(sheetId, row) {
|
|
36753
|
+
return Math.round(this.getters.getUserRowSize(sheetId, row) ??
|
|
36754
|
+
this.tallestCellInRow[sheetId][row]?.size ??
|
|
36755
|
+
DEFAULT_CELL_HEIGHT);
|
|
36756
|
+
}
|
|
36757
|
+
updateRowSizeForCellChange(sheetId, row, col) {
|
|
36758
|
+
const tallestCellInRow = this.tallestCellInRow[sheetId]?.[row];
|
|
36759
|
+
if (tallestCellInRow?.cell.col === col) {
|
|
36760
|
+
const newTallestCell = this.getRowTallestCell(sheetId, row);
|
|
36761
|
+
this.history.update("tallestCellInRow", sheetId, row, newTallestCell);
|
|
36762
|
+
}
|
|
36763
|
+
const updatedCellHeight = this.getCellHeight({ sheetId, col, row });
|
|
36764
|
+
if (updatedCellHeight <= DEFAULT_CELL_HEIGHT) {
|
|
36765
|
+
return;
|
|
36766
|
+
}
|
|
36767
|
+
if ((!tallestCellInRow && updatedCellHeight > DEFAULT_CELL_HEIGHT) ||
|
|
36768
|
+
(tallestCellInRow && updatedCellHeight > tallestCellInRow.size)) {
|
|
36769
|
+
const newTallestCell = { cell: { sheetId, col, row }, size: updatedCellHeight };
|
|
36770
|
+
this.history.update("tallestCellInRow", sheetId, row, newTallestCell);
|
|
36771
|
+
}
|
|
36772
|
+
}
|
|
36773
|
+
initializeSheet(sheetId) {
|
|
36774
|
+
const tallestCells = [];
|
|
36775
|
+
for (let row = 0; row < this.getters.getNumberRows(sheetId); row++) {
|
|
36776
|
+
const tallestCell = this.getRowTallestCell(sheetId, row);
|
|
36777
|
+
tallestCells.push(tallestCell);
|
|
36778
|
+
}
|
|
36779
|
+
this.history.update("tallestCellInRow", sheetId, tallestCells);
|
|
36780
|
+
}
|
|
36781
|
+
/**
|
|
36782
|
+
* Return the height the cell should have in the sheet, which is either DEFAULT_CELL_HEIGHT if the cell is in a multi-row
|
|
36783
|
+
* merge, or the height of the cell computed based on its style/content.
|
|
36784
|
+
*/
|
|
36785
|
+
getCellHeight(position) {
|
|
36786
|
+
if (this.isInMultiRowMerge(position)) {
|
|
36787
|
+
return DEFAULT_CELL_HEIGHT;
|
|
36788
|
+
}
|
|
36789
|
+
const cell = this.getters.getCell(position);
|
|
36790
|
+
const colSize = this.getters.getColSize(position.sheetId, position.col);
|
|
36791
|
+
return getDefaultCellHeight(this.ctx, cell, colSize);
|
|
36792
|
+
}
|
|
36793
|
+
isInMultiRowMerge(position) {
|
|
36794
|
+
const merge = this.getters.getMerge(position);
|
|
36795
|
+
return !!merge && merge.bottom !== merge.top;
|
|
36796
|
+
}
|
|
36797
|
+
/**
|
|
36798
|
+
* Get the tallest cell of a row and its size.
|
|
36799
|
+
*/
|
|
36800
|
+
getRowTallestCell(sheetId, row) {
|
|
36801
|
+
const userRowSize = this.getters.getUserRowSize(sheetId, row);
|
|
36802
|
+
if (userRowSize !== undefined) {
|
|
36803
|
+
return undefined;
|
|
36804
|
+
}
|
|
36805
|
+
const cellIds = this.getters.getRowCells(sheetId, row);
|
|
36806
|
+
let maxHeight = 0;
|
|
36807
|
+
let tallestCell = undefined;
|
|
36808
|
+
for (let i = 0; i < cellIds.length; i++) {
|
|
36809
|
+
const cell = this.getters.getCellById(cellIds[i]);
|
|
36810
|
+
if (!cell) {
|
|
36811
|
+
continue;
|
|
36812
|
+
}
|
|
36813
|
+
const position = this.getters.getCellPosition(cell.id);
|
|
36814
|
+
const cellHeight = this.getCellHeight(position);
|
|
36815
|
+
if (cellHeight > maxHeight && cellHeight > DEFAULT_CELL_HEIGHT) {
|
|
36816
|
+
maxHeight = cellHeight;
|
|
36817
|
+
tallestCell = { cell: position, size: cellHeight };
|
|
36818
|
+
}
|
|
36819
|
+
}
|
|
36820
|
+
if (tallestCell && tallestCell.size > DEFAULT_CELL_HEIGHT) {
|
|
36821
|
+
return tallestCell;
|
|
36822
|
+
}
|
|
36823
|
+
return undefined;
|
|
36824
|
+
}
|
|
36825
|
+
}
|
|
36826
|
+
|
|
36599
36827
|
/**
|
|
36600
36828
|
* This plugin manage the autofill.
|
|
36601
36829
|
*
|
|
@@ -38297,6 +38525,7 @@
|
|
|
38297
38525
|
searchFormulas: false,
|
|
38298
38526
|
};
|
|
38299
38527
|
toSearch = "";
|
|
38528
|
+
isSearchDirty = false;
|
|
38300
38529
|
// ---------------------------------------------------------------------------
|
|
38301
38530
|
// Command Handling
|
|
38302
38531
|
// ---------------------------------------------------------------------------
|
|
@@ -38324,14 +38553,21 @@
|
|
|
38324
38553
|
case "REDO":
|
|
38325
38554
|
case "REMOVE_COLUMNS_ROWS":
|
|
38326
38555
|
case "ADD_COLUMNS_ROWS":
|
|
38327
|
-
|
|
38556
|
+
case "EVALUATE_CELLS":
|
|
38557
|
+
case "UPDATE_CELL":
|
|
38558
|
+
this.isSearchDirty = true;
|
|
38328
38559
|
break;
|
|
38329
38560
|
case "ACTIVATE_SHEET":
|
|
38330
|
-
case "REFRESH_SEARCH":
|
|
38331
38561
|
this.refreshSearch();
|
|
38332
38562
|
break;
|
|
38333
38563
|
}
|
|
38334
38564
|
}
|
|
38565
|
+
finalize() {
|
|
38566
|
+
if (this.isSearchDirty) {
|
|
38567
|
+
this.refreshSearch();
|
|
38568
|
+
this.isSearchDirty = false;
|
|
38569
|
+
}
|
|
38570
|
+
}
|
|
38335
38571
|
// ---------------------------------------------------------------------------
|
|
38336
38572
|
// Getters
|
|
38337
38573
|
// ---------------------------------------------------------------------------
|
|
@@ -38387,6 +38623,11 @@
|
|
|
38387
38623
|
if (this.toSearch) {
|
|
38388
38624
|
for (const cell of Object.values(cells)) {
|
|
38389
38625
|
const { col, row } = this.getters.getCellPosition(cell.id);
|
|
38626
|
+
const isColHidden = this.getters.isColHidden(sheetId, col);
|
|
38627
|
+
const isRowHidden = this.getters.isRowHidden(sheetId, row);
|
|
38628
|
+
if (isColHidden || isRowHidden) {
|
|
38629
|
+
continue;
|
|
38630
|
+
}
|
|
38390
38631
|
if (cell &&
|
|
38391
38632
|
this.currentSearchRegex &&
|
|
38392
38633
|
this.currentSearchRegex.test(this.getSearchableString({ sheetId, col, row }))) {
|
|
@@ -40029,10 +40270,8 @@
|
|
|
40029
40270
|
}
|
|
40030
40271
|
updateCellCommands.push(newCellValues);
|
|
40031
40272
|
}
|
|
40032
|
-
for (const cmd of updateCellCommands) {
|
|
40033
|
-
this.dispatch("UPDATE_CELL", cmd);
|
|
40034
|
-
}
|
|
40035
40273
|
}
|
|
40274
|
+
updateCellCommands.forEach((cmdPayload) => this.dispatch("UPDATE_CELL", cmdPayload));
|
|
40036
40275
|
}
|
|
40037
40276
|
/**
|
|
40038
40277
|
* Return the distances between main merge cells in the zone.
|
|
@@ -40133,24 +40372,28 @@
|
|
|
40133
40372
|
// Getters
|
|
40134
40373
|
// ---------------------------------------------------------------------------
|
|
40135
40374
|
getCellWidth(position) {
|
|
40136
|
-
const text = this.getCellText(position);
|
|
40137
40375
|
const style = this.getters.getCellComputedStyle(position);
|
|
40138
|
-
|
|
40139
|
-
|
|
40376
|
+
let contentWidth = 0;
|
|
40377
|
+
const content = this.getters.getEvaluatedCell(position).formattedValue;
|
|
40378
|
+
if (content) {
|
|
40379
|
+
const multiLineText = splitTextToWidth(this.ctx, content, style, undefined);
|
|
40380
|
+
contentWidth += Math.max(...multiLineText.map((line) => computeTextWidth(this.ctx, line, style)));
|
|
40381
|
+
}
|
|
40140
40382
|
const icon = this.getters.getConditionalIcon(position);
|
|
40141
40383
|
if (icon) {
|
|
40142
|
-
contentWidth += computeIconWidth(
|
|
40384
|
+
contentWidth += computeIconWidth(style);
|
|
40143
40385
|
}
|
|
40144
40386
|
const isFilterHeader = this.getters.isFilterHeader(position);
|
|
40145
40387
|
if (isFilterHeader) {
|
|
40146
40388
|
contentWidth += ICON_EDGE_LENGTH + FILTER_ICON_MARGIN;
|
|
40147
40389
|
}
|
|
40148
|
-
if (contentWidth
|
|
40149
|
-
|
|
40150
|
-
|
|
40151
|
-
|
|
40152
|
-
|
|
40153
|
-
|
|
40390
|
+
if (contentWidth === 0) {
|
|
40391
|
+
return 0;
|
|
40392
|
+
}
|
|
40393
|
+
contentWidth += 2 * PADDING_AUTORESIZE_HORIZONTAL;
|
|
40394
|
+
if (style.wrapping === "wrap") {
|
|
40395
|
+
const colWidth = this.getters.getColSize(this.getters.getActiveSheetId(), position.col);
|
|
40396
|
+
return Math.min(colWidth, contentWidth);
|
|
40154
40397
|
}
|
|
40155
40398
|
return contentWidth;
|
|
40156
40399
|
}
|
|
@@ -40173,56 +40416,7 @@
|
|
|
40173
40416
|
getCellMultiLineText(position, width) {
|
|
40174
40417
|
const style = this.getters.getCellStyle(position);
|
|
40175
40418
|
const text = this.getters.getCellText(position, this.getters.shouldShowFormulas());
|
|
40176
|
-
|
|
40177
|
-
for (const line of text.split("\n")) {
|
|
40178
|
-
const words = line.split(" ");
|
|
40179
|
-
if (!width) {
|
|
40180
|
-
brokenText.push(line);
|
|
40181
|
-
continue;
|
|
40182
|
-
}
|
|
40183
|
-
let textLine = "";
|
|
40184
|
-
let availableWidth = width;
|
|
40185
|
-
for (let word of words) {
|
|
40186
|
-
const splitWord = this.splitWordToSpecificWidth(this.ctx, word, width, style);
|
|
40187
|
-
const lastPart = splitWord.pop();
|
|
40188
|
-
const lastPartWidth = computeTextWidth(this.ctx, lastPart, style);
|
|
40189
|
-
// At this step: "splitWord" is an array composed of parts of word whose
|
|
40190
|
-
// length is at most equal to "width".
|
|
40191
|
-
// Last part contains the end of the word.
|
|
40192
|
-
// Note that: When word length is less than width, then lastPart is equal
|
|
40193
|
-
// to word and splitWord is empty
|
|
40194
|
-
if (splitWord.length) {
|
|
40195
|
-
if (textLine !== "") {
|
|
40196
|
-
brokenText.push(textLine);
|
|
40197
|
-
textLine = "";
|
|
40198
|
-
availableWidth = width;
|
|
40199
|
-
}
|
|
40200
|
-
splitWord.forEach((wordPart) => {
|
|
40201
|
-
brokenText.push(wordPart);
|
|
40202
|
-
});
|
|
40203
|
-
textLine = lastPart;
|
|
40204
|
-
availableWidth = width - lastPartWidth;
|
|
40205
|
-
}
|
|
40206
|
-
else {
|
|
40207
|
-
// here "lastPart" is equal to "word" and the "word" size is smaller than "width"
|
|
40208
|
-
const _word = textLine === "" ? lastPart : " " + lastPart;
|
|
40209
|
-
const wordWidth = computeTextWidth(this.ctx, _word, style);
|
|
40210
|
-
if (wordWidth <= availableWidth) {
|
|
40211
|
-
textLine += _word;
|
|
40212
|
-
availableWidth -= wordWidth;
|
|
40213
|
-
}
|
|
40214
|
-
else {
|
|
40215
|
-
brokenText.push(textLine);
|
|
40216
|
-
textLine = lastPart;
|
|
40217
|
-
availableWidth = width - lastPartWidth;
|
|
40218
|
-
}
|
|
40219
|
-
}
|
|
40220
|
-
}
|
|
40221
|
-
if (textLine !== "") {
|
|
40222
|
-
brokenText.push(textLine);
|
|
40223
|
-
}
|
|
40224
|
-
}
|
|
40225
|
-
return brokenText;
|
|
40419
|
+
return splitTextToWidth(this.ctx, text, style, width);
|
|
40226
40420
|
}
|
|
40227
40421
|
/**
|
|
40228
40422
|
* Returns the size, start and end coordinates of a column on an unfolded sheet
|
|
@@ -40281,26 +40475,6 @@
|
|
|
40281
40475
|
const sizes = cellsPositions.map((position) => this.getCellWidth({ sheetId, ...position }));
|
|
40282
40476
|
return Math.max(0, ...sizes);
|
|
40283
40477
|
}
|
|
40284
|
-
splitWordToSpecificWidth(ctx, word, width, style) {
|
|
40285
|
-
const wordWidth = computeTextWidth(ctx, word, style);
|
|
40286
|
-
if (wordWidth <= width) {
|
|
40287
|
-
return [word];
|
|
40288
|
-
}
|
|
40289
|
-
const splitWord = [];
|
|
40290
|
-
let wordPart = "";
|
|
40291
|
-
for (let l of word) {
|
|
40292
|
-
const wordPartWidth = computeTextWidth(ctx, wordPart + l, style);
|
|
40293
|
-
if (wordPartWidth > width) {
|
|
40294
|
-
splitWord.push(wordPart);
|
|
40295
|
-
wordPart = l;
|
|
40296
|
-
}
|
|
40297
|
-
else {
|
|
40298
|
-
wordPart += l;
|
|
40299
|
-
}
|
|
40300
|
-
}
|
|
40301
|
-
splitWord.push(wordPart);
|
|
40302
|
-
return splitWord;
|
|
40303
|
-
}
|
|
40304
40478
|
/**
|
|
40305
40479
|
* Check that any "sheetId" in the command matches an existing
|
|
40306
40480
|
* sheet.
|
|
@@ -41292,7 +41466,7 @@
|
|
|
41292
41466
|
.join("\n") || "\t");
|
|
41293
41467
|
}
|
|
41294
41468
|
getHTMLContent() {
|
|
41295
|
-
if (this.cells.length
|
|
41469
|
+
if (this.cells.length === 1 && this.cells[0].length === 1) {
|
|
41296
41470
|
return this.getters.getCellText(this.cells[0][0].position);
|
|
41297
41471
|
}
|
|
41298
41472
|
let htmlTable = '<table border="1" style="border-collapse:collapse">';
|
|
@@ -41617,7 +41791,7 @@
|
|
|
41617
41791
|
status = "invisible";
|
|
41618
41792
|
state;
|
|
41619
41793
|
lastPasteState;
|
|
41620
|
-
|
|
41794
|
+
paintFormatStatus = "inactive";
|
|
41621
41795
|
originSheetId;
|
|
41622
41796
|
// ---------------------------------------------------------------------------
|
|
41623
41797
|
// Command Handling
|
|
@@ -41632,7 +41806,7 @@
|
|
|
41632
41806
|
if (!this.state) {
|
|
41633
41807
|
return 24 /* CommandResult.EmptyClipboard */;
|
|
41634
41808
|
}
|
|
41635
|
-
const pasteOption = cmd.pasteOption || (this.
|
|
41809
|
+
const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
|
|
41636
41810
|
return this.state.isPasteAllowed(cmd.target, { pasteOption });
|
|
41637
41811
|
case "PASTE_FROM_OS_CLIPBOARD": {
|
|
41638
41812
|
const state = new ClipboardOsState(cmd.text, this.getters, this.dispatch, this.selection);
|
|
@@ -41648,6 +41822,11 @@
|
|
|
41648
41822
|
const state = this.getClipboardStateForCopyCells(cut, "CUT");
|
|
41649
41823
|
return state.isPasteAllowed(paste);
|
|
41650
41824
|
}
|
|
41825
|
+
case "ACTIVATE_PAINT_FORMAT": {
|
|
41826
|
+
if (this.paintFormatStatus !== "inactive") {
|
|
41827
|
+
return 95 /* CommandResult.AlreadyInPaintingFormatMode */;
|
|
41828
|
+
}
|
|
41829
|
+
}
|
|
41651
41830
|
}
|
|
41652
41831
|
return 0 /* CommandResult.Success */;
|
|
41653
41832
|
}
|
|
@@ -41664,11 +41843,13 @@
|
|
|
41664
41843
|
if (!this.state) {
|
|
41665
41844
|
break;
|
|
41666
41845
|
}
|
|
41667
|
-
const pasteOption = cmd.pasteOption || (this.
|
|
41668
|
-
this._isPaintingFormat = false;
|
|
41846
|
+
const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
|
|
41669
41847
|
this.state.paste(cmd.target, { pasteOption, shouldPasteCF: true, selectTarget: true });
|
|
41670
41848
|
this.lastPasteState = this.state;
|
|
41671
|
-
this.
|
|
41849
|
+
if (this.paintFormatStatus === "oneOff") {
|
|
41850
|
+
this.paintFormatStatus = "inactive";
|
|
41851
|
+
this.status = "invisible";
|
|
41852
|
+
}
|
|
41672
41853
|
break;
|
|
41673
41854
|
case "CLEAN_CLIPBOARD_HIGHLIGHT":
|
|
41674
41855
|
this.status = "invisible";
|
|
@@ -41736,8 +41917,13 @@
|
|
|
41736
41917
|
case "ACTIVATE_PAINT_FORMAT": {
|
|
41737
41918
|
const zones = this.getters.getSelectedZones();
|
|
41738
41919
|
this.state = this.getClipboardStateForCopyCells(zones, "COPY");
|
|
41739
|
-
this._isPaintingFormat = true;
|
|
41740
41920
|
this.status = "visible";
|
|
41921
|
+
if (cmd.persistent) {
|
|
41922
|
+
this.paintFormatStatus = "persistent";
|
|
41923
|
+
}
|
|
41924
|
+
else {
|
|
41925
|
+
this.paintFormatStatus = "oneOff";
|
|
41926
|
+
}
|
|
41741
41927
|
break;
|
|
41742
41928
|
}
|
|
41743
41929
|
case "DELETE_SHEET":
|
|
@@ -41749,6 +41935,11 @@
|
|
|
41749
41935
|
this.status = "invisible";
|
|
41750
41936
|
}
|
|
41751
41937
|
break;
|
|
41938
|
+
case "CANCEL_PAINT_FORMAT": {
|
|
41939
|
+
this.paintFormatStatus = "inactive";
|
|
41940
|
+
this.status = "invisible";
|
|
41941
|
+
break;
|
|
41942
|
+
}
|
|
41752
41943
|
default:
|
|
41753
41944
|
if (isCoreCommand(cmd)) {
|
|
41754
41945
|
this.status = "invisible";
|
|
@@ -41779,7 +41970,7 @@
|
|
|
41779
41970
|
return this.state ? this.state.operation === "CUT" : false;
|
|
41780
41971
|
}
|
|
41781
41972
|
isPaintingFormat() {
|
|
41782
|
-
return this.
|
|
41973
|
+
return this.paintFormatStatus !== "inactive";
|
|
41783
41974
|
}
|
|
41784
41975
|
// ---------------------------------------------------------------------------
|
|
41785
41976
|
// Private methods
|
|
@@ -44414,6 +44605,7 @@
|
|
|
44414
44605
|
.add("evaluation", EvaluationPlugin)
|
|
44415
44606
|
.add("evaluation_chart", EvaluationChartPlugin)
|
|
44416
44607
|
.add("evaluation_cf", EvaluationConditionalFormatPlugin)
|
|
44608
|
+
.add("row_size", UIRowSizePlugin)
|
|
44417
44609
|
.add("custom_colors", CustomColorsPlugin);
|
|
44418
44610
|
|
|
44419
44611
|
const clickableCellRegistry = new Registry();
|
|
@@ -45536,6 +45728,11 @@
|
|
|
45536
45728
|
.o-sidePanelButton:enabled {
|
|
45537
45729
|
cursor: pointer;
|
|
45538
45730
|
}
|
|
45731
|
+
|
|
45732
|
+
.o-sidePanelButton:disabled {
|
|
45733
|
+
color: ${DISABLED_TEXT_COLOR};
|
|
45734
|
+
}
|
|
45735
|
+
|
|
45539
45736
|
.o-sidePanelButton:last-child {
|
|
45540
45737
|
margin-right: 0px;
|
|
45541
45738
|
}
|
|
@@ -45669,11 +45866,11 @@
|
|
|
45669
45866
|
}
|
|
45670
45867
|
get title() {
|
|
45671
45868
|
const name = this.actionButton.name(this.env);
|
|
45672
|
-
const description = this.actionButton.description;
|
|
45869
|
+
const description = this.actionButton.description(this.env);
|
|
45673
45870
|
return name + (description ? ` (${description})` : "");
|
|
45674
45871
|
}
|
|
45675
45872
|
get iconTitle() {
|
|
45676
|
-
return this.actionButton.icon;
|
|
45873
|
+
return this.actionButton.icon(this.env);
|
|
45677
45874
|
}
|
|
45678
45875
|
onClick(ev) {
|
|
45679
45876
|
if (this.isEnabled) {
|
|
@@ -46058,6 +46255,27 @@
|
|
|
46058
46255
|
class: String,
|
|
46059
46256
|
};
|
|
46060
46257
|
|
|
46258
|
+
class PaintFormatButton extends owl.Component {
|
|
46259
|
+
static template = "o-spreadsheet-PaintFormatButton";
|
|
46260
|
+
get isActive() {
|
|
46261
|
+
return this.env.model.getters.isPaintingFormat();
|
|
46262
|
+
}
|
|
46263
|
+
onDblClick() {
|
|
46264
|
+
this.env.model.dispatch("ACTIVATE_PAINT_FORMAT", { persistent: true });
|
|
46265
|
+
}
|
|
46266
|
+
togglePaintFormat() {
|
|
46267
|
+
if (this.isActive) {
|
|
46268
|
+
this.env.model.dispatch("CANCEL_PAINT_FORMAT");
|
|
46269
|
+
}
|
|
46270
|
+
else {
|
|
46271
|
+
this.env.model.dispatch("ACTIVATE_PAINT_FORMAT", { persistent: false });
|
|
46272
|
+
}
|
|
46273
|
+
}
|
|
46274
|
+
}
|
|
46275
|
+
PaintFormatButton.props = {
|
|
46276
|
+
class: { type: String, optional: true },
|
|
46277
|
+
};
|
|
46278
|
+
|
|
46061
46279
|
// -----------------------------------------------------------------------------
|
|
46062
46280
|
// TopBar
|
|
46063
46281
|
// -----------------------------------------------------------------------------
|
|
@@ -46158,6 +46376,7 @@
|
|
|
46158
46376
|
TopBarComposer,
|
|
46159
46377
|
FontSizeEditor,
|
|
46160
46378
|
ActionButton,
|
|
46379
|
+
PaintFormatButton,
|
|
46161
46380
|
BorderEditorWidget,
|
|
46162
46381
|
};
|
|
46163
46382
|
state = owl.useState({
|
|
@@ -48010,7 +48229,7 @@
|
|
|
48010
48229
|
: "nextCluster";
|
|
48011
48230
|
while (true) {
|
|
48012
48231
|
const nextCellPosition = this.getNextCellPosition(currentPosition, dim, dir);
|
|
48013
|
-
// Break if nextPosition
|
|
48232
|
+
// Break if nextPosition === currentPosition, which happens if there's no next valid position
|
|
48014
48233
|
if (currentPosition.col === nextCellPosition.col &&
|
|
48015
48234
|
currentPosition.row === nextCellPosition.row) {
|
|
48016
48235
|
break;
|
|
@@ -49924,6 +50143,7 @@
|
|
|
49924
50143
|
...config,
|
|
49925
50144
|
mode: config.mode || "normal",
|
|
49926
50145
|
custom: config.custom || {},
|
|
50146
|
+
defaultCurrencyFormat: config.defaultCurrencyFormat || "[$$]#,##0.00",
|
|
49927
50147
|
external: this.setupExternalConfig(config.external || {}),
|
|
49928
50148
|
transportService,
|
|
49929
50149
|
client,
|
|
@@ -50221,6 +50441,7 @@
|
|
|
50221
50441
|
numberToLetters,
|
|
50222
50442
|
UuidGenerator,
|
|
50223
50443
|
formatValue,
|
|
50444
|
+
createCurrencyFormat,
|
|
50224
50445
|
computeTextWidth,
|
|
50225
50446
|
createEmptyWorkbookData,
|
|
50226
50447
|
createEmptySheet,
|
|
@@ -50306,9 +50527,9 @@
|
|
|
50306
50527
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
50307
50528
|
|
|
50308
50529
|
|
|
50309
|
-
__info__.version = '16.4.
|
|
50310
|
-
__info__.date = '2023-07-
|
|
50311
|
-
__info__.hash = '
|
|
50530
|
+
__info__.version = '16.4.1';
|
|
50531
|
+
__info__.date = '2023-07-26T12:13:04.992Z';
|
|
50532
|
+
__info__.hash = 'e687fa9';
|
|
50312
50533
|
|
|
50313
50534
|
|
|
50314
50535
|
})(this.o_spreadsheet = this.o_spreadsheet || {}, owl);
|