@odoo/o-spreadsheet 17.1.0-alpha.3 → 17.1.0-alpha.5
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 +769 -520
- package/dist/o-spreadsheet.d.ts +164 -164
- package/dist/o-spreadsheet.esm.js +769 -520
- package/dist/o-spreadsheet.iife.js +769 -520
- package/dist/o-spreadsheet.iife.min.js +299 -327
- package/dist/o_spreadsheet.xml +100 -62
- package/package.json +1 -1
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* This file is generated by o-spreadsheet build tools. Do not edit it.
|
|
4
4
|
* @see https://github.com/odoo/o-spreadsheet
|
|
5
|
-
* @version 17.1.0-alpha.
|
|
6
|
-
* @date 2023-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 17.1.0-alpha.5
|
|
6
|
+
* @date 2023-12-05T09:51:40.034Z
|
|
7
|
+
* @hash c2823eb
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
'use strict';
|
|
@@ -229,7 +229,6 @@ const DEFAULT_CELL_HEIGHT = 23;
|
|
|
229
229
|
const SCROLLBAR_WIDTH = 15;
|
|
230
230
|
const AUTOFILL_EDGE_LENGTH = 8;
|
|
231
231
|
const ICON_EDGE_LENGTH = 18;
|
|
232
|
-
const UNHIDE_ICON_EDGE_LENGTH = 14;
|
|
233
232
|
const MIN_CF_ICON_MARGIN = 4;
|
|
234
233
|
const MIN_CELL_TEXT_MARGIN = 4;
|
|
235
234
|
const CF_ICON_EDGE_LENGTH = 15;
|
|
@@ -693,8 +692,7 @@ function removeFalsyAttributes(obj) {
|
|
|
693
692
|
*
|
|
694
693
|
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes
|
|
695
694
|
*/
|
|
696
|
-
const
|
|
697
|
-
" ",
|
|
695
|
+
const whiteSpaceSpecialCharacters = [
|
|
698
696
|
"\t",
|
|
699
697
|
"\f",
|
|
700
698
|
"\v",
|
|
@@ -709,8 +707,7 @@ const whiteSpaceCharacters = [
|
|
|
709
707
|
String.fromCharCode(parseInt("3000", 16)),
|
|
710
708
|
String.fromCharCode(parseInt("feff", 16)),
|
|
711
709
|
];
|
|
712
|
-
const whiteSpaceRegexp = new RegExp(
|
|
713
|
-
const newLineRegex = /\r\n|\r|\n/g;
|
|
710
|
+
const whiteSpaceRegexp = new RegExp(whiteSpaceSpecialCharacters.join("|") + "|(\r\n|\r|\n)", "g");
|
|
714
711
|
/**
|
|
715
712
|
* Replace all the special spaces in a string (non-breaking, tabs, ...) by normal spaces, and all the
|
|
716
713
|
* different newlines types by \n.
|
|
@@ -718,9 +715,9 @@ const newLineRegex = /\r\n|\r|\n/g;
|
|
|
718
715
|
function replaceSpecialSpaces(text) {
|
|
719
716
|
if (!text)
|
|
720
717
|
return "";
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
return text;
|
|
718
|
+
if (!whiteSpaceRegexp.test(text))
|
|
719
|
+
return text;
|
|
720
|
+
return text.replace(whiteSpaceRegexp, (match, newLine) => (newLine ? NEWLINE : " "));
|
|
724
721
|
}
|
|
725
722
|
/**
|
|
726
723
|
* Determine if the numbers are consecutive.
|
|
@@ -2062,6 +2059,7 @@ exports.CommandResult = void 0;
|
|
|
2062
2059
|
CommandResult["InvalidNumberOfCriterionValues"] = "InvalidNumberOfCriterionValues";
|
|
2063
2060
|
CommandResult["BlockingValidationRule"] = "BlockingValidationRule";
|
|
2064
2061
|
CommandResult["InvalidCopyPasteSelection"] = "InvalidCopyPasteSelection";
|
|
2062
|
+
CommandResult["NoChanges"] = "NoChanges";
|
|
2065
2063
|
})(exports.CommandResult || (exports.CommandResult = {}));
|
|
2066
2064
|
|
|
2067
2065
|
const DEFAULT_LOCALES = [
|
|
@@ -2191,12 +2189,12 @@ function toString(value) {
|
|
|
2191
2189
|
}
|
|
2192
2190
|
}
|
|
2193
2191
|
/** Normalize string by setting it to lowercase and replacing accent letters with plain letters */
|
|
2194
|
-
function normalizeString(str) {
|
|
2192
|
+
const normalizeString = memoize(function normalizeString(str) {
|
|
2195
2193
|
return str
|
|
2196
2194
|
.toLowerCase()
|
|
2197
2195
|
.normalize("NFD")
|
|
2198
2196
|
.replace(/[\u0300-\u036f]/g, "");
|
|
2199
|
-
}
|
|
2197
|
+
});
|
|
2200
2198
|
const expectBooleanValueError = (value) => _t("The function [[FUNCTION_NAME]] expects a boolean value, but '%s' is a text, and cannot be coerced to a number.", value);
|
|
2201
2199
|
function toBoolean(value) {
|
|
2202
2200
|
switch (typeof value) {
|
|
@@ -3390,8 +3388,10 @@ function convertInternalFormatToFormat(internalFormat) {
|
|
|
3390
3388
|
const cellReference = new RegExp(/\$?([A-Z]{1,3})\$?([0-9]{1,7})/, "i");
|
|
3391
3389
|
// Same as above, but matches the exact string (nothing before or after)
|
|
3392
3390
|
const singleCellReference = new RegExp(/^\$?([A-Z]{1,3})\$?([0-9]{1,7})$/, "i");
|
|
3393
|
-
/** Reference of a column header (eg. A, AB) */
|
|
3394
|
-
const colHeader = new RegExp(
|
|
3391
|
+
/** Reference of a column header (eg. A, AB, $A) */
|
|
3392
|
+
const colHeader = new RegExp(/^\$?([A-Z]{1,3})+$/, "i");
|
|
3393
|
+
/** Reference of a row header (eg. 1, $1) */
|
|
3394
|
+
const rowHeader = new RegExp(/^\$?([0-9]{1,7})+$/, "i");
|
|
3395
3395
|
/** Reference of a column (eg. A, $CA, Sheet1!B) */
|
|
3396
3396
|
const colReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([A-Z]{1,3})$/, "i");
|
|
3397
3397
|
/** Reference of a row (eg. 1, 59, Sheet1!9) */
|
|
@@ -3421,6 +3421,9 @@ function isRowReference(xc) {
|
|
|
3421
3421
|
function isColHeader(str) {
|
|
3422
3422
|
return colHeader.test(str);
|
|
3423
3423
|
}
|
|
3424
|
+
function isRowHeader(str) {
|
|
3425
|
+
return rowHeader.test(str);
|
|
3426
|
+
}
|
|
3424
3427
|
/**
|
|
3425
3428
|
* Return true if the given xc is the reference of a single cell,
|
|
3426
3429
|
* without any specified sheet (e.g. A1)
|
|
@@ -3429,11 +3432,18 @@ function isSingleCellReference(xc) {
|
|
|
3429
3432
|
return singleCellReference.test(xc);
|
|
3430
3433
|
}
|
|
3431
3434
|
function splitReference(ref) {
|
|
3435
|
+
if (!ref.includes("!")) {
|
|
3436
|
+
return { xc: ref };
|
|
3437
|
+
}
|
|
3432
3438
|
const parts = ref.split("!");
|
|
3433
3439
|
const xc = parts.pop();
|
|
3434
3440
|
const sheetName = getUnquotedSheetName(parts.join("!")) || undefined;
|
|
3435
3441
|
return { sheetName, xc };
|
|
3436
3442
|
}
|
|
3443
|
+
/** Return a reference SheetName!xc from the given arguments */
|
|
3444
|
+
function getFullReference(sheetName, xc) {
|
|
3445
|
+
return sheetName !== undefined ? `${getCanonicalSheetName(sheetName)}!${xc}` : xc;
|
|
3446
|
+
}
|
|
3437
3447
|
|
|
3438
3448
|
/**
|
|
3439
3449
|
* Convert from a cartesian reference to a Zone
|
|
@@ -4104,18 +4114,10 @@ class RangeImpl {
|
|
|
4104
4114
|
if (isFullCol) {
|
|
4105
4115
|
parts[0].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
|
|
4106
4116
|
parts[1].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
|
|
4107
|
-
if (zone.left === zone.right) {
|
|
4108
|
-
parts[0].colFixed = parts[0].colFixed || parts[1].colFixed;
|
|
4109
|
-
parts[1].colFixed = parts[0].colFixed || parts[1].colFixed;
|
|
4110
|
-
}
|
|
4111
4117
|
}
|
|
4112
4118
|
if (isFullRow) {
|
|
4113
4119
|
parts[0].colFixed = parts[0].colFixed || parts[1].colFixed;
|
|
4114
4120
|
parts[1].colFixed = parts[0].colFixed || parts[1].colFixed;
|
|
4115
|
-
if (zone.top === zone.bottom) {
|
|
4116
|
-
parts[0].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
|
|
4117
|
-
parts[1].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
|
|
4118
|
-
}
|
|
4119
4121
|
}
|
|
4120
4122
|
return parts;
|
|
4121
4123
|
}
|
|
@@ -4357,7 +4359,7 @@ function computeTextLinesHeight(textLineHeight, numberOfLines = 1) {
|
|
|
4357
4359
|
function getDefaultCellHeight(ctx, cell, colSize) {
|
|
4358
4360
|
if (!cell || !cell.content)
|
|
4359
4361
|
return DEFAULT_CELL_HEIGHT;
|
|
4360
|
-
const maxWidth = cell.style?.wrapping ? colSize - 2 * MIN_CELL_TEXT_MARGIN : undefined;
|
|
4362
|
+
const maxWidth = cell.style?.wrapping === "wrap" ? colSize - 2 * MIN_CELL_TEXT_MARGIN : undefined;
|
|
4361
4363
|
const numberOfLines = cell.isFormula
|
|
4362
4364
|
? 1
|
|
4363
4365
|
: splitTextToWidth(ctx, cell.content, cell.style, maxWidth).length;
|
|
@@ -4542,14 +4544,14 @@ function drawDecoratedText(context, text, position, underline = false, strikethr
|
|
|
4542
4544
|
switch (context.textBaseline) {
|
|
4543
4545
|
case "top":
|
|
4544
4546
|
underlineY += boxHeight - 2 * strokeWidth;
|
|
4545
|
-
strikeY += boxHeight -
|
|
4547
|
+
strikeY += boxHeight / 2 - strokeWidth;
|
|
4546
4548
|
break;
|
|
4547
4549
|
case "middle":
|
|
4548
4550
|
underlineY += boxHeight / 2 - strokeWidth;
|
|
4549
4551
|
break;
|
|
4550
4552
|
case "alphabetic":
|
|
4551
4553
|
underlineY += 2 * strokeWidth;
|
|
4552
|
-
strikeY -=
|
|
4554
|
+
strikeY -= 3 * strokeWidth;
|
|
4553
4555
|
break;
|
|
4554
4556
|
case "bottom":
|
|
4555
4557
|
underlineY = y;
|
|
@@ -4612,6 +4614,7 @@ function createAction(item) {
|
|
|
4612
4614
|
const children = item.children;
|
|
4613
4615
|
const description = item.description;
|
|
4614
4616
|
const icon = item.icon;
|
|
4617
|
+
const secondaryIcon = item.secondaryIcon;
|
|
4615
4618
|
return {
|
|
4616
4619
|
id: item.id || uuidGenerator$2.uuidv4(),
|
|
4617
4620
|
name: typeof name === "function" ? name : () => name,
|
|
@@ -4630,6 +4633,7 @@ function createAction(item) {
|
|
|
4630
4633
|
isReadonlyAllowed: item.isReadonlyAllowed || false,
|
|
4631
4634
|
separator: item.separator || false,
|
|
4632
4635
|
icon: typeof icon === "function" ? icon : () => icon || "",
|
|
4636
|
+
secondaryIcon: typeof secondaryIcon === "function" ? secondaryIcon : () => secondaryIcon || "",
|
|
4633
4637
|
description: typeof description === "function" ? description : () => description || "",
|
|
4634
4638
|
textColor: item.textColor,
|
|
4635
4639
|
sequence: item.sequence || 0,
|
|
@@ -6252,10 +6256,6 @@ css /* scss */ `
|
|
|
6252
6256
|
|
|
6253
6257
|
.o-error-tooltip-message {
|
|
6254
6258
|
overflow: hidden;
|
|
6255
|
-
display: -webkit-box; /* Limit to 3 lines */
|
|
6256
|
-
-webkit-line-clamp: 3;
|
|
6257
|
-
line-clamp: 3;
|
|
6258
|
-
-webkit-box-orient: vertical;
|
|
6259
6259
|
}
|
|
6260
6260
|
}
|
|
6261
6261
|
`;
|
|
@@ -6663,6 +6663,9 @@ function keyboardEventToShortcutString(ev, mode = "key") {
|
|
|
6663
6663
|
keyDownString += letterRegex.test(key) ? key.toUpperCase() : key;
|
|
6664
6664
|
return keyDownString;
|
|
6665
6665
|
}
|
|
6666
|
+
function isMacOS() {
|
|
6667
|
+
return navigator.userAgent.toUpperCase().indexOf("MAC") >= 0;
|
|
6668
|
+
}
|
|
6666
6669
|
|
|
6667
6670
|
/**
|
|
6668
6671
|
* Return the o-spreadsheet element position relative
|
|
@@ -6985,11 +6988,9 @@ css /* scss */ `
|
|
|
6985
6988
|
padding: ${MENU_VERTICAL_PADDING}px 0px;
|
|
6986
6989
|
width: ${MENU_WIDTH}px;
|
|
6987
6990
|
box-sizing: border-box !important;
|
|
6991
|
+
user-select: none;
|
|
6988
6992
|
|
|
6989
6993
|
.o-menu-item {
|
|
6990
|
-
display: flex;
|
|
6991
|
-
justify-content: space-between;
|
|
6992
|
-
align-items: center;
|
|
6993
6994
|
box-sizing: border-box;
|
|
6994
6995
|
height: ${MENU_ITEM_HEIGHT}px;
|
|
6995
6996
|
padding: ${MENU_ITEM_PADDING_VERTICAL}px ${MENU_ITEM_PADDING_HORIZONTAL}px;
|
|
@@ -7000,20 +7001,12 @@ css /* scss */ `
|
|
|
7000
7001
|
min-width: 40%;
|
|
7001
7002
|
}
|
|
7002
7003
|
|
|
7003
|
-
&.o-menu-root {
|
|
7004
|
-
display: flex;
|
|
7005
|
-
justify-content: space-between;
|
|
7006
|
-
}
|
|
7007
|
-
|
|
7008
7004
|
.o-menu-item-icon {
|
|
7009
7005
|
display: inline-block;
|
|
7010
7006
|
margin: 0px 8px 0px 0px;
|
|
7011
7007
|
width: ${MENU_ITEM_HEIGHT - 2 * MENU_ITEM_PADDING_VERTICAL}px;
|
|
7012
7008
|
line-height: ${MENU_ITEM_HEIGHT - 2 * MENU_ITEM_PADDING_VERTICAL}px;
|
|
7013
7009
|
}
|
|
7014
|
-
.o-menu-item-root {
|
|
7015
|
-
width: 10px;
|
|
7016
|
-
}
|
|
7017
7010
|
|
|
7018
7011
|
&:not(.disabled) {
|
|
7019
7012
|
&:hover,
|
|
@@ -7356,7 +7349,7 @@ function tokenize(str, locale = DEFAULT_LOCALE) {
|
|
|
7356
7349
|
return result;
|
|
7357
7350
|
}
|
|
7358
7351
|
function tokenizeDebugger(chars) {
|
|
7359
|
-
if (chars.current
|
|
7352
|
+
if (chars.current === "?") {
|
|
7360
7353
|
chars.shift();
|
|
7361
7354
|
return { type: "DEBUGGER", value: "?" };
|
|
7362
7355
|
}
|
|
@@ -7367,7 +7360,7 @@ const misc$1 = {
|
|
|
7367
7360
|
")": "RIGHT_PAREN",
|
|
7368
7361
|
};
|
|
7369
7362
|
function tokenizeMisc(chars) {
|
|
7370
|
-
if (chars.current
|
|
7363
|
+
if (chars.current in misc$1) {
|
|
7371
7364
|
const value = chars.shift();
|
|
7372
7365
|
const type = misc$1[value];
|
|
7373
7366
|
return { type, value };
|
|
@@ -7375,7 +7368,7 @@ function tokenizeMisc(chars) {
|
|
|
7375
7368
|
return null;
|
|
7376
7369
|
}
|
|
7377
7370
|
function tokenizeArgsSeparator(chars, locale) {
|
|
7378
|
-
if (chars.current
|
|
7371
|
+
if (chars.current === locale.formulaArgSeparator) {
|
|
7379
7372
|
const value = chars.shift();
|
|
7380
7373
|
const type = "ARG_SEPARATOR";
|
|
7381
7374
|
return { type, value };
|
|
@@ -7400,14 +7393,13 @@ function tokenizeNumber(chars, locale) {
|
|
|
7400
7393
|
return null;
|
|
7401
7394
|
}
|
|
7402
7395
|
function tokenizeString(chars) {
|
|
7403
|
-
if (chars.current
|
|
7396
|
+
if (chars.current === '"') {
|
|
7404
7397
|
const startChar = chars.shift();
|
|
7405
7398
|
let letters = startChar;
|
|
7406
|
-
while (chars.current()
|
|
7407
|
-
(chars.current() !== startChar || letters[letters.length - 1] === "\\")) {
|
|
7399
|
+
while (chars.current && (chars.current !== startChar || letters[letters.length - 1] === "\\")) {
|
|
7408
7400
|
letters += chars.shift();
|
|
7409
7401
|
}
|
|
7410
|
-
if (chars.current
|
|
7402
|
+
if (chars.current === '"') {
|
|
7411
7403
|
letters += chars.shift();
|
|
7412
7404
|
}
|
|
7413
7405
|
return {
|
|
@@ -7434,14 +7426,14 @@ function tokenizeSymbol(chars) {
|
|
|
7434
7426
|
let result = "";
|
|
7435
7427
|
// there are two main cases to manage: either something which starts with
|
|
7436
7428
|
// a ', like 'Sheet 2'A2, or a word-like element.
|
|
7437
|
-
if (chars.current
|
|
7429
|
+
if (chars.current === "'") {
|
|
7438
7430
|
let lastChar = chars.shift();
|
|
7439
7431
|
result += lastChar;
|
|
7440
|
-
while (chars.current
|
|
7432
|
+
while (chars.current) {
|
|
7441
7433
|
lastChar = chars.shift();
|
|
7442
7434
|
result += lastChar;
|
|
7443
7435
|
if (lastChar === "'") {
|
|
7444
|
-
if (chars.current
|
|
7436
|
+
if (chars.current && chars.current === "'") {
|
|
7445
7437
|
lastChar = chars.shift();
|
|
7446
7438
|
result += lastChar;
|
|
7447
7439
|
}
|
|
@@ -7457,7 +7449,7 @@ function tokenizeSymbol(chars) {
|
|
|
7457
7449
|
};
|
|
7458
7450
|
}
|
|
7459
7451
|
}
|
|
7460
|
-
while (chars.current
|
|
7452
|
+
while (chars.current && separatorRegexp.test(chars.current)) {
|
|
7461
7453
|
result += chars.shift();
|
|
7462
7454
|
}
|
|
7463
7455
|
if (result.length) {
|
|
@@ -7472,14 +7464,14 @@ function tokenizeSymbol(chars) {
|
|
|
7472
7464
|
}
|
|
7473
7465
|
function tokenizeSpace(chars) {
|
|
7474
7466
|
let length = 0;
|
|
7475
|
-
while (chars.current
|
|
7467
|
+
while (chars.current === NEWLINE) {
|
|
7476
7468
|
length++;
|
|
7477
7469
|
chars.shift();
|
|
7478
7470
|
}
|
|
7479
7471
|
if (length) {
|
|
7480
7472
|
return { type: "SPACE", value: NEWLINE.repeat(length) };
|
|
7481
7473
|
}
|
|
7482
|
-
while (chars.current
|
|
7474
|
+
while (chars.current === " ") {
|
|
7483
7475
|
length++;
|
|
7484
7476
|
chars.shift();
|
|
7485
7477
|
}
|
|
@@ -7498,17 +7490,20 @@ function tokenizeInvalidRange(chars) {
|
|
|
7498
7490
|
class TokenizingChars {
|
|
7499
7491
|
text;
|
|
7500
7492
|
currentIndex = 0;
|
|
7493
|
+
current;
|
|
7501
7494
|
constructor(text) {
|
|
7502
7495
|
this.text = text;
|
|
7503
|
-
|
|
7504
|
-
current() {
|
|
7505
|
-
return this.text[this.currentIndex];
|
|
7496
|
+
this.current = text[0];
|
|
7506
7497
|
}
|
|
7507
7498
|
shift() {
|
|
7508
|
-
|
|
7499
|
+
const current = this.current;
|
|
7500
|
+
const next = this.text[++this.currentIndex];
|
|
7501
|
+
this.current = next;
|
|
7502
|
+
return current;
|
|
7509
7503
|
}
|
|
7510
7504
|
advanceBy(length) {
|
|
7511
7505
|
this.currentIndex += length;
|
|
7506
|
+
this.current = this.text[this.currentIndex];
|
|
7512
7507
|
}
|
|
7513
7508
|
isOver() {
|
|
7514
7509
|
return this.currentIndex >= this.text.length;
|
|
@@ -11312,7 +11307,7 @@ const EXPAND = {
|
|
|
11312
11307
|
) {
|
|
11313
11308
|
const _array = toMatrix(arg);
|
|
11314
11309
|
const _nbRows = toInteger(rows?.value, this.locale);
|
|
11315
|
-
const _nbColumns = columns !== undefined ? toInteger(columns.value, this.
|
|
11310
|
+
const _nbColumns = columns !== undefined ? toInteger(columns.value, this.locale) : _array.length;
|
|
11316
11311
|
assert(() => _nbRows >= _array[0].length, _t("The rows arguments (%s) must be greater or equal than the number of rows of the array.", _nbRows.toString()));
|
|
11317
11312
|
assert(() => _nbColumns >= _array.length, _t("The columns arguments (%s) must be greater or equal than the number of columns of the array.", _nbColumns.toString()));
|
|
11318
11313
|
return generateMatrix(_nbColumns, _nbRows, (col, row) => col >= _array.length || row >= _array[col].length ? padWith : _array[col][row]);
|
|
@@ -11801,6 +11796,10 @@ var misc = /*#__PURE__*/Object.freeze({
|
|
|
11801
11796
|
FORMAT_LARGE_NUMBER: FORMAT_LARGE_NUMBER
|
|
11802
11797
|
});
|
|
11803
11798
|
|
|
11799
|
+
function sum(values, locale) {
|
|
11800
|
+
return reduceNumbers(values, (acc, a) => acc + a, 0, locale);
|
|
11801
|
+
}
|
|
11802
|
+
|
|
11804
11803
|
const DEFAULT_FACTOR = 1;
|
|
11805
11804
|
const DEFAULT_MODE = 0;
|
|
11806
11805
|
const DEFAULT_PLACES = 0;
|
|
@@ -12752,7 +12751,7 @@ const SUM = {
|
|
|
12752
12751
|
return isMatrix(value1) ? value1[0][0]?.format : value1?.format;
|
|
12753
12752
|
},
|
|
12754
12753
|
compute: function (...values) {
|
|
12755
|
-
return
|
|
12754
|
+
return sum(values, this.locale);
|
|
12756
12755
|
},
|
|
12757
12756
|
isExported: true,
|
|
12758
12757
|
};
|
|
@@ -12921,6 +12920,44 @@ function assertSameNumberOfElements(...args) {
|
|
|
12921
12920
|
const dims = args[0].length;
|
|
12922
12921
|
args.forEach((arg, i) => assert(() => arg.length === dims, _t("[[FUNCTION_NAME]] has mismatched dimensions for argument %s (%s vs %s).", i.toString(), dims.toString(), arg.length.toString())));
|
|
12923
12922
|
}
|
|
12923
|
+
function average(values, locale) {
|
|
12924
|
+
let count = 0;
|
|
12925
|
+
const sum = reduceNumbers(values, (acc, a) => {
|
|
12926
|
+
count += 1;
|
|
12927
|
+
return acc + a;
|
|
12928
|
+
}, 0, locale);
|
|
12929
|
+
assert(() => count !== 0, _t("Evaluation of function [[FUNCTION_NAME]] caused a divide by zero error."));
|
|
12930
|
+
return sum / count;
|
|
12931
|
+
}
|
|
12932
|
+
function countNumbers(values, locale) {
|
|
12933
|
+
let count = 0;
|
|
12934
|
+
for (let n of values) {
|
|
12935
|
+
if (isMatrix(n)) {
|
|
12936
|
+
for (let i of n) {
|
|
12937
|
+
for (let j of i) {
|
|
12938
|
+
if (typeof j === "number") {
|
|
12939
|
+
count += 1;
|
|
12940
|
+
}
|
|
12941
|
+
}
|
|
12942
|
+
}
|
|
12943
|
+
}
|
|
12944
|
+
else if (typeof n !== "string" || isNumber(n, locale) || parseDateTime(n, locale)) {
|
|
12945
|
+
count += 1;
|
|
12946
|
+
}
|
|
12947
|
+
}
|
|
12948
|
+
return count;
|
|
12949
|
+
}
|
|
12950
|
+
function countAny(values) {
|
|
12951
|
+
return reduceAny(values, (acc, a) => (a !== undefined && a !== null ? acc + 1 : acc), 0);
|
|
12952
|
+
}
|
|
12953
|
+
function max(values, locale) {
|
|
12954
|
+
const result = reduceNumbers(values, (acc, a) => (acc < a ? a : acc), -Infinity, locale);
|
|
12955
|
+
return result === -Infinity ? 0 : result;
|
|
12956
|
+
}
|
|
12957
|
+
function min(values, locale) {
|
|
12958
|
+
const result = reduceNumbers(values, (acc, a) => (a < acc ? a : acc), Infinity, locale);
|
|
12959
|
+
return result === Infinity ? 0 : result;
|
|
12960
|
+
}
|
|
12924
12961
|
|
|
12925
12962
|
function filterAndFlatData(dataY, dataX) {
|
|
12926
12963
|
const _flatDataY = [];
|
|
@@ -13191,13 +13228,7 @@ const AVERAGE = {
|
|
|
13191
13228
|
return isMatrix(value1) ? value1[0][0]?.format : value1?.format;
|
|
13192
13229
|
},
|
|
13193
13230
|
compute: function (...values) {
|
|
13194
|
-
|
|
13195
|
-
const sum = reduceNumbers(values, (acc, a) => {
|
|
13196
|
-
count += 1;
|
|
13197
|
-
return acc + a;
|
|
13198
|
-
}, 0, this.locale);
|
|
13199
|
-
assert(() => count !== 0, _t("Evaluation of function [[FUNCTION_NAME]] caused a divide by zero error."));
|
|
13200
|
-
return sum / count;
|
|
13231
|
+
return average(values, this.locale);
|
|
13201
13232
|
},
|
|
13202
13233
|
isExported: true,
|
|
13203
13234
|
};
|
|
@@ -13355,24 +13386,7 @@ const COUNT = {
|
|
|
13355
13386
|
],
|
|
13356
13387
|
returns: ["NUMBER"],
|
|
13357
13388
|
compute: function (...values) {
|
|
13358
|
-
|
|
13359
|
-
for (let n of values) {
|
|
13360
|
-
if (isMatrix(n)) {
|
|
13361
|
-
for (let i of n) {
|
|
13362
|
-
for (let j of i) {
|
|
13363
|
-
if (typeof j === "number") {
|
|
13364
|
-
count += 1;
|
|
13365
|
-
}
|
|
13366
|
-
}
|
|
13367
|
-
}
|
|
13368
|
-
}
|
|
13369
|
-
else if (typeof n !== "string" ||
|
|
13370
|
-
isNumber(n, this.locale) ||
|
|
13371
|
-
parseDateTime(n, this.locale)) {
|
|
13372
|
-
count += 1;
|
|
13373
|
-
}
|
|
13374
|
-
}
|
|
13375
|
-
return count;
|
|
13389
|
+
return countNumbers(values, this.locale);
|
|
13376
13390
|
},
|
|
13377
13391
|
isExported: true,
|
|
13378
13392
|
};
|
|
@@ -13387,7 +13401,7 @@ const COUNTA = {
|
|
|
13387
13401
|
],
|
|
13388
13402
|
returns: ["NUMBER"],
|
|
13389
13403
|
compute: function (...values) {
|
|
13390
|
-
return
|
|
13404
|
+
return countAny(values);
|
|
13391
13405
|
},
|
|
13392
13406
|
isExported: true,
|
|
13393
13407
|
};
|
|
@@ -13617,8 +13631,7 @@ const MAX = {
|
|
|
13617
13631
|
return isMatrix(value1) ? value1[0][0]?.format : value1?.format;
|
|
13618
13632
|
},
|
|
13619
13633
|
compute: function (...values) {
|
|
13620
|
-
|
|
13621
|
-
return result === -Infinity ? 0 : result;
|
|
13634
|
+
return max(values, this.locale);
|
|
13622
13635
|
},
|
|
13623
13636
|
isExported: true,
|
|
13624
13637
|
};
|
|
@@ -13705,8 +13718,7 @@ const MIN = {
|
|
|
13705
13718
|
return isMatrix(value1) ? value1[0][0]?.format : value1?.format;
|
|
13706
13719
|
},
|
|
13707
13720
|
compute: function (...values) {
|
|
13708
|
-
|
|
13709
|
-
return result === Infinity ? 0 : result;
|
|
13721
|
+
return min(values, this.locale);
|
|
13710
13722
|
},
|
|
13711
13723
|
isExported: true,
|
|
13712
13724
|
};
|
|
@@ -17877,6 +17889,153 @@ var financial = /*#__PURE__*/Object.freeze({
|
|
|
17877
17889
|
YIELDMAT: YIELDMAT
|
|
17878
17890
|
});
|
|
17879
17891
|
|
|
17892
|
+
/**
|
|
17893
|
+
* Change the reference types inside the given token, if the token represent a range or a cell
|
|
17894
|
+
*
|
|
17895
|
+
* Eg. :
|
|
17896
|
+
* A1 => $A$1 => A$1 => $A1 => A1
|
|
17897
|
+
* A1:$B$1 => $A$1:B$1 => A$1:$B1 => $A1:B1 => A1:$B$1
|
|
17898
|
+
*/
|
|
17899
|
+
function loopThroughReferenceType(token) {
|
|
17900
|
+
if (token.type !== "REFERENCE")
|
|
17901
|
+
return token;
|
|
17902
|
+
const { xc, sheetName } = splitReference(token.value);
|
|
17903
|
+
const [left, right] = xc.split(":");
|
|
17904
|
+
const updatedLeft = getTokenNextReferenceType(left);
|
|
17905
|
+
const updatedRight = right ? `:${getTokenNextReferenceType(right)}` : "";
|
|
17906
|
+
return { ...token, value: getFullReference(sheetName, updatedLeft + updatedRight) };
|
|
17907
|
+
}
|
|
17908
|
+
/**
|
|
17909
|
+
* Get a new token with a changed type of reference from the given cell token symbol.
|
|
17910
|
+
* Undefined behavior if given a token other than a cell or if the Xc contains a sheet reference
|
|
17911
|
+
*
|
|
17912
|
+
* A1 => $A$1 => A$1 => $A1 => A1
|
|
17913
|
+
*/
|
|
17914
|
+
function getTokenNextReferenceType(xc) {
|
|
17915
|
+
switch (getReferenceType(xc)) {
|
|
17916
|
+
case "none":
|
|
17917
|
+
xc = setXcToFixedReferenceType(xc, "colrow");
|
|
17918
|
+
break;
|
|
17919
|
+
case "colrow":
|
|
17920
|
+
xc = setXcToFixedReferenceType(xc, "row");
|
|
17921
|
+
break;
|
|
17922
|
+
case "row":
|
|
17923
|
+
xc = setXcToFixedReferenceType(xc, "col");
|
|
17924
|
+
break;
|
|
17925
|
+
case "col":
|
|
17926
|
+
xc = setXcToFixedReferenceType(xc, "none");
|
|
17927
|
+
break;
|
|
17928
|
+
}
|
|
17929
|
+
return xc;
|
|
17930
|
+
}
|
|
17931
|
+
/**
|
|
17932
|
+
* Returns the given XC with the given reference type. The XC string should not contain a sheet name.
|
|
17933
|
+
*/
|
|
17934
|
+
function setXcToFixedReferenceType(xc, referenceType) {
|
|
17935
|
+
if (xc.includes("!")) {
|
|
17936
|
+
throw new Error("The given XC should not contain a sheet name");
|
|
17937
|
+
}
|
|
17938
|
+
xc = xc.replace(/\$/g, "");
|
|
17939
|
+
let indexOfNumber;
|
|
17940
|
+
switch (referenceType) {
|
|
17941
|
+
case "col":
|
|
17942
|
+
return "$" + xc;
|
|
17943
|
+
case "row":
|
|
17944
|
+
indexOfNumber = xc.search(/[0-9]/);
|
|
17945
|
+
return xc.slice(0, indexOfNumber) + "$" + xc.slice(indexOfNumber);
|
|
17946
|
+
case "colrow":
|
|
17947
|
+
indexOfNumber = xc.search(/[0-9]/);
|
|
17948
|
+
if (indexOfNumber === -1 || indexOfNumber === 0) {
|
|
17949
|
+
// no row number (eg. A) or no column (eg. 1)
|
|
17950
|
+
return "$" + xc;
|
|
17951
|
+
}
|
|
17952
|
+
xc = xc.slice(0, indexOfNumber) + "$" + xc.slice(indexOfNumber);
|
|
17953
|
+
return "$" + xc;
|
|
17954
|
+
case "none":
|
|
17955
|
+
return xc;
|
|
17956
|
+
}
|
|
17957
|
+
}
|
|
17958
|
+
/**
|
|
17959
|
+
* Return the type of reference used in the given XC of a cell.
|
|
17960
|
+
* Undefined behavior if the XC have a sheet reference
|
|
17961
|
+
*/
|
|
17962
|
+
function getReferenceType(xcCell) {
|
|
17963
|
+
if (isColAndRowFixed(xcCell)) {
|
|
17964
|
+
return "colrow";
|
|
17965
|
+
}
|
|
17966
|
+
else if (isColFixed(xcCell)) {
|
|
17967
|
+
return "col";
|
|
17968
|
+
}
|
|
17969
|
+
else if (isRowFixed(xcCell)) {
|
|
17970
|
+
return "row";
|
|
17971
|
+
}
|
|
17972
|
+
return "none";
|
|
17973
|
+
}
|
|
17974
|
+
function isColFixed(xc) {
|
|
17975
|
+
return xc.startsWith("$");
|
|
17976
|
+
}
|
|
17977
|
+
function isRowFixed(xc) {
|
|
17978
|
+
return xc.includes("$", 1);
|
|
17979
|
+
}
|
|
17980
|
+
function isColAndRowFixed(xc) {
|
|
17981
|
+
return xc.startsWith("$") && xc.length > 1 && xc.slice(1).includes("$");
|
|
17982
|
+
}
|
|
17983
|
+
|
|
17984
|
+
// -----------------------------------------------------------------------------
|
|
17985
|
+
// CELL
|
|
17986
|
+
// -----------------------------------------------------------------------------
|
|
17987
|
+
// NOTE: missing from Excel: "color", "filename", "parentheses", "prefix", "protect" and "width"
|
|
17988
|
+
const CELL_INFO_TYPES = ["address", "col", "contents", "format", "row", "type"];
|
|
17989
|
+
const CELL = {
|
|
17990
|
+
description: _t("Gets information about a cell."),
|
|
17991
|
+
args: [
|
|
17992
|
+
arg("info_type (string)", _t("The type of information requested. Can be one of %s", CELL_INFO_TYPES.join(", "))),
|
|
17993
|
+
arg("reference (meta)", _t("The reference to the cell.")),
|
|
17994
|
+
],
|
|
17995
|
+
returns: ["ANY"],
|
|
17996
|
+
compute: function (info, reference) {
|
|
17997
|
+
const _info = toString(info).toLowerCase();
|
|
17998
|
+
assert(() => CELL_INFO_TYPES.includes(_info), _t("The info_type should be one of %s.", CELL_INFO_TYPES.join(", ")));
|
|
17999
|
+
const sheetId = this.__originSheetId;
|
|
18000
|
+
const topLeftReference = reference.includes(":") ? reference.split(":")[0] : reference;
|
|
18001
|
+
let { sheetName, xc } = splitReference(topLeftReference);
|
|
18002
|
+
// only put the sheet name if the referenced range is in another sheet than the cell the formula is on
|
|
18003
|
+
sheetName = sheetName === this.getters.getSheetName(sheetId) ? undefined : sheetName;
|
|
18004
|
+
const fixedRef = getFullReference(sheetName, setXcToFixedReferenceType(xc, "colrow"));
|
|
18005
|
+
const range = this.getters.getRangeFromSheetXC(sheetId, fixedRef);
|
|
18006
|
+
switch (_info) {
|
|
18007
|
+
case "address":
|
|
18008
|
+
return this.getters.getRangeString(range, sheetId);
|
|
18009
|
+
case "col":
|
|
18010
|
+
return range.zone.left + 1;
|
|
18011
|
+
case "contents": {
|
|
18012
|
+
const position = { sheetId: range.sheetId, col: range.zone.left, row: range.zone.top };
|
|
18013
|
+
return this.getters.getEvaluatedCell(position).value;
|
|
18014
|
+
}
|
|
18015
|
+
case "format": {
|
|
18016
|
+
const position = { sheetId: range.sheetId, col: range.zone.left, row: range.zone.top };
|
|
18017
|
+
return this.getters.getEvaluatedCell(position).format || "";
|
|
18018
|
+
}
|
|
18019
|
+
case "row":
|
|
18020
|
+
return range.zone.top + 1;
|
|
18021
|
+
case "type": {
|
|
18022
|
+
const position = { sheetId: range.sheetId, col: range.zone.left, row: range.zone.top };
|
|
18023
|
+
const type = this.getters.getEvaluatedCell(position).type;
|
|
18024
|
+
if (type === CellValueType.empty) {
|
|
18025
|
+
return "b"; // blank
|
|
18026
|
+
}
|
|
18027
|
+
else if (type === CellValueType.text) {
|
|
18028
|
+
return "l"; // label
|
|
18029
|
+
}
|
|
18030
|
+
else {
|
|
18031
|
+
return "v"; // value
|
|
18032
|
+
}
|
|
18033
|
+
}
|
|
18034
|
+
}
|
|
18035
|
+
return "";
|
|
18036
|
+
},
|
|
18037
|
+
isExported: true,
|
|
18038
|
+
};
|
|
17880
18039
|
// -----------------------------------------------------------------------------
|
|
17881
18040
|
// ISERR
|
|
17882
18041
|
// -----------------------------------------------------------------------------
|
|
@@ -18032,6 +18191,7 @@ const NA = {
|
|
|
18032
18191
|
|
|
18033
18192
|
var info = /*#__PURE__*/Object.freeze({
|
|
18034
18193
|
__proto__: null,
|
|
18194
|
+
CELL: CELL,
|
|
18035
18195
|
ISBLANK: ISBLANK,
|
|
18036
18196
|
ISERR: ISERR,
|
|
18037
18197
|
ISERROR: ISERROR,
|
|
@@ -18323,7 +18483,7 @@ const ADDRESS = {
|
|
|
18323
18483
|
cellReference = rowPart + colPart;
|
|
18324
18484
|
}
|
|
18325
18485
|
if (sheet !== undefined) {
|
|
18326
|
-
return
|
|
18486
|
+
return getFullReference(toString(sheet), cellReference);
|
|
18327
18487
|
}
|
|
18328
18488
|
return cellReference;
|
|
18329
18489
|
},
|
|
@@ -18339,7 +18499,7 @@ const COLUMN = {
|
|
|
18339
18499
|
],
|
|
18340
18500
|
returns: ["NUMBER"],
|
|
18341
18501
|
compute: function (cellReference) {
|
|
18342
|
-
const _cellReference = cellReference || this.__originCellXC
|
|
18502
|
+
const _cellReference = cellReference || this.__originCellXC();
|
|
18343
18503
|
assert(() => !!_cellReference, "In this context, the function [[FUNCTION_NAME]] needs to have a cell or range in parameter.");
|
|
18344
18504
|
const zone = toZone(_cellReference);
|
|
18345
18505
|
return zone.left + 1;
|
|
@@ -18506,7 +18666,7 @@ const ROW = {
|
|
|
18506
18666
|
],
|
|
18507
18667
|
returns: ["NUMBER"],
|
|
18508
18668
|
compute: function (cellReference) {
|
|
18509
|
-
cellReference = cellReference || this.__originCellXC
|
|
18669
|
+
cellReference = cellReference || this.__originCellXC();
|
|
18510
18670
|
assert(() => !!cellReference, "In this context, the function [[FUNCTION_NAME]] needs to have a cell or range in parameter.");
|
|
18511
18671
|
const zone = toZone(cellReference);
|
|
18512
18672
|
return zone.top + 1;
|
|
@@ -23858,31 +24018,65 @@ css /* scss */ `
|
|
|
23858
24018
|
`;
|
|
23859
24019
|
class FindAndReplacePanel extends owl.Component {
|
|
23860
24020
|
static template = "o-spreadsheet-FindAndReplacePanel";
|
|
23861
|
-
|
|
24021
|
+
static components = { SelectionInput };
|
|
23862
24022
|
debounceTimeoutId;
|
|
23863
|
-
|
|
24023
|
+
initialShowFormulaState = false;
|
|
24024
|
+
dataRange = "";
|
|
23864
24025
|
searchInput = owl.useRef("searchInput");
|
|
24026
|
+
replaceInput = owl.useRef("replaceInput");
|
|
23865
24027
|
get hasSearchResult() {
|
|
23866
24028
|
return this.env.model.getters.getCurrentSelectedMatchIndex() !== null;
|
|
23867
24029
|
}
|
|
23868
24030
|
get pendingSearch() {
|
|
23869
24031
|
return this.debounceTimeoutId !== undefined;
|
|
23870
24032
|
}
|
|
24033
|
+
get searchOptions() {
|
|
24034
|
+
return this.env.model.getters.getSearchOptions();
|
|
24035
|
+
}
|
|
24036
|
+
get toSearch() {
|
|
24037
|
+
return this.searchInput.el?.value || "";
|
|
24038
|
+
}
|
|
24039
|
+
get toReplace() {
|
|
24040
|
+
return this.replaceInput.el?.value || "";
|
|
24041
|
+
}
|
|
24042
|
+
get allSheetsMatchesCount() {
|
|
24043
|
+
return _t("%s in all sheets", this.env.model.getters.getAllSheetMatchesCount());
|
|
24044
|
+
}
|
|
24045
|
+
get currentSheetMatchesCount() {
|
|
24046
|
+
return _t("%(matches)s in sheet %(sheetName)s", {
|
|
24047
|
+
matches: this.env.model.getters.getActiveSheetMatchesCount(),
|
|
24048
|
+
sheetName: this.env.model.getters.getSheetName(this.env.model.getters.getActiveSheetId()),
|
|
24049
|
+
});
|
|
24050
|
+
}
|
|
24051
|
+
get specificRangeMatchesCount() {
|
|
24052
|
+
const range = this.searchOptions.specificRange;
|
|
24053
|
+
if (!range) {
|
|
24054
|
+
return "";
|
|
24055
|
+
}
|
|
24056
|
+
const { _sheetId, _zone } = range;
|
|
24057
|
+
return _t("%(matches)s in range %(range)s of sheet %(sheetName)s", {
|
|
24058
|
+
matches: this.env.model.getters.getSpecificRangeMatchesCount().toString(),
|
|
24059
|
+
range: zoneToXc(_zone),
|
|
24060
|
+
sheetName: this.env.model.getters.getSheetName(_sheetId),
|
|
24061
|
+
});
|
|
24062
|
+
}
|
|
23871
24063
|
setup() {
|
|
23872
|
-
this.
|
|
24064
|
+
this.initialShowFormulaState = this.env.model.getters.shouldShowFormulas();
|
|
23873
24065
|
owl.onMounted(() => this.searchInput.el?.focus());
|
|
23874
24066
|
owl.onWillUnmount(() => {
|
|
23875
24067
|
clearTimeout(this.debounceTimeoutId);
|
|
23876
24068
|
this.env.model.dispatch("CLEAR_SEARCH");
|
|
23877
|
-
this.env.model.dispatch("SET_FORMULA_VISIBILITY", { show: this.
|
|
24069
|
+
this.env.model.dispatch("SET_FORMULA_VISIBILITY", { show: this.initialShowFormulaState });
|
|
23878
24070
|
});
|
|
23879
24071
|
owl.useEffect(() => {
|
|
23880
|
-
|
|
23881
|
-
this.searchFormulas
|
|
24072
|
+
const showFormula = this.env.model.getters.shouldShowFormulas();
|
|
24073
|
+
this.updateSearch({ searchFormulas: showFormula });
|
|
23882
24074
|
}, () => [this.env.model.getters.shouldShowFormulas()]);
|
|
23883
24075
|
}
|
|
23884
|
-
|
|
23885
|
-
this.
|
|
24076
|
+
onFocusSearch() {
|
|
24077
|
+
this.updateDataRange();
|
|
24078
|
+
}
|
|
24079
|
+
onInput() {
|
|
23886
24080
|
this.debouncedUpdateSearch();
|
|
23887
24081
|
}
|
|
23888
24082
|
onKeydownSearch(ev) {
|
|
@@ -23899,11 +24093,36 @@ class FindAndReplacePanel extends owl.Component {
|
|
|
23899
24093
|
this.replace();
|
|
23900
24094
|
}
|
|
23901
24095
|
}
|
|
23902
|
-
searchFormulas() {
|
|
24096
|
+
searchFormulas(ev) {
|
|
24097
|
+
const showFormula = ev.target.checked;
|
|
23903
24098
|
this.env.model.dispatch("SET_FORMULA_VISIBILITY", {
|
|
23904
|
-
show:
|
|
24099
|
+
show: showFormula,
|
|
23905
24100
|
});
|
|
23906
|
-
this.updateSearch();
|
|
24101
|
+
this.updateSearch({ searchFormulas: showFormula });
|
|
24102
|
+
}
|
|
24103
|
+
searchExactMatch(ev) {
|
|
24104
|
+
const exactMatch = ev.target.checked;
|
|
24105
|
+
this.updateSearch({ exactMatch });
|
|
24106
|
+
}
|
|
24107
|
+
searchMatchCase(ev) {
|
|
24108
|
+
const matchCase = ev.target.checked;
|
|
24109
|
+
this.updateSearch({ matchCase });
|
|
24110
|
+
}
|
|
24111
|
+
changeSearchScope(ev) {
|
|
24112
|
+
const searchScope = ev.target.value;
|
|
24113
|
+
this.updateSearch({ searchScope });
|
|
24114
|
+
}
|
|
24115
|
+
onSearchRangeChanged(ranges) {
|
|
24116
|
+
this.dataRange = ranges[0];
|
|
24117
|
+
}
|
|
24118
|
+
updateDataRange() {
|
|
24119
|
+
if (!this.dataRange) {
|
|
24120
|
+
return;
|
|
24121
|
+
}
|
|
24122
|
+
if (this.searchOptions.searchScope === "specificRange") {
|
|
24123
|
+
const specificRange = this.env.model.getters.getRangeFromSheetXC(this.env.model.getters.getActiveSheetId(), this.dataRange).rangeData;
|
|
24124
|
+
this.updateSearch({ specificRange });
|
|
24125
|
+
}
|
|
23907
24126
|
}
|
|
23908
24127
|
onSelectPreviousCell() {
|
|
23909
24128
|
this.env.model.dispatch("SELECT_SEARCH_PREVIOUS_MATCH");
|
|
@@ -23911,10 +24130,14 @@ class FindAndReplacePanel extends owl.Component {
|
|
|
23911
24130
|
onSelectNextCell() {
|
|
23912
24131
|
this.env.model.dispatch("SELECT_SEARCH_NEXT_MATCH");
|
|
23913
24132
|
}
|
|
23914
|
-
updateSearch() {
|
|
24133
|
+
updateSearch(updateSearchOptions) {
|
|
24134
|
+
const searchOptions = {
|
|
24135
|
+
...this.env.model.getters.getSearchOptions(),
|
|
24136
|
+
...updateSearchOptions,
|
|
24137
|
+
};
|
|
23915
24138
|
this.env.model.dispatch("UPDATE_SEARCH", {
|
|
23916
|
-
toSearch: this.
|
|
23917
|
-
searchOptions
|
|
24139
|
+
toSearch: this.toSearch,
|
|
24140
|
+
searchOptions,
|
|
23918
24141
|
});
|
|
23919
24142
|
}
|
|
23920
24143
|
debouncedUpdateSearch() {
|
|
@@ -23926,28 +24149,14 @@ class FindAndReplacePanel extends owl.Component {
|
|
|
23926
24149
|
}
|
|
23927
24150
|
replace() {
|
|
23928
24151
|
this.env.model.dispatch("REPLACE_SEARCH", {
|
|
23929
|
-
replaceWith: this.
|
|
24152
|
+
replaceWith: this.toReplace,
|
|
23930
24153
|
});
|
|
23931
24154
|
}
|
|
23932
24155
|
replaceAll() {
|
|
23933
24156
|
this.env.model.dispatch("REPLACE_ALL_SEARCH", {
|
|
23934
|
-
replaceWith: this.
|
|
24157
|
+
replaceWith: this.toReplace,
|
|
23935
24158
|
});
|
|
23936
24159
|
}
|
|
23937
|
-
// ---------------------------------------------------------------------------
|
|
23938
|
-
// Private
|
|
23939
|
-
// ---------------------------------------------------------------------------
|
|
23940
|
-
initialState() {
|
|
23941
|
-
return {
|
|
23942
|
-
toSearch: "",
|
|
23943
|
-
replaceWith: "",
|
|
23944
|
-
searchOptions: {
|
|
23945
|
-
matchCase: false,
|
|
23946
|
-
exactMatch: false,
|
|
23947
|
-
searchFormulas: false,
|
|
23948
|
-
},
|
|
23949
|
-
};
|
|
23950
|
-
}
|
|
23951
24160
|
}
|
|
23952
24161
|
FindAndReplacePanel.props = {
|
|
23953
24162
|
onCloseSidePanel: Function,
|
|
@@ -27093,7 +27302,7 @@ class GridComposer extends owl.Component {
|
|
|
27093
27302
|
get cellReference() {
|
|
27094
27303
|
const { col, row, sheetId } = this.env.model.getters.getCurrentEditedCell();
|
|
27095
27304
|
const prefixSheet = sheetId !== this.env.model.getters.getActiveSheetId();
|
|
27096
|
-
return
|
|
27305
|
+
return getFullReference(prefixSheet ? this.env.model.getters.getSheetName(sheetId) : undefined, toXC(col, row));
|
|
27097
27306
|
}
|
|
27098
27307
|
get cellReferenceStyle() {
|
|
27099
27308
|
const { x: left, y: top } = this.rect;
|
|
@@ -28310,6 +28519,7 @@ class AbstractResizer extends owl.Component {
|
|
|
28310
28519
|
draggerShadowThickness: 0,
|
|
28311
28520
|
delta: 0,
|
|
28312
28521
|
base: 0,
|
|
28522
|
+
position: "before",
|
|
28313
28523
|
});
|
|
28314
28524
|
_computeHandleDisplay(ev) {
|
|
28315
28525
|
const position = this._getEvOffset(ev);
|
|
@@ -28434,11 +28644,13 @@ class AbstractResizer extends owl.Component {
|
|
|
28434
28644
|
this.state.draggerLinePosition = dimensions.start;
|
|
28435
28645
|
this.state.draggerShadowPosition = dimensions.start;
|
|
28436
28646
|
this.state.base = elementIndex;
|
|
28647
|
+
this.state.position = "before";
|
|
28437
28648
|
}
|
|
28438
28649
|
else if (this._getSelectedZoneEnd() < elementIndex) {
|
|
28439
28650
|
this.state.draggerLinePosition = dimensions.end;
|
|
28440
28651
|
this.state.draggerShadowPosition = dimensions.end - this.state.draggerShadowThickness;
|
|
28441
|
-
this.state.base = elementIndex
|
|
28652
|
+
this.state.base = elementIndex;
|
|
28653
|
+
this.state.position = "after";
|
|
28442
28654
|
}
|
|
28443
28655
|
else {
|
|
28444
28656
|
this.state.draggerLinePosition = startDimensions.start;
|
|
@@ -28536,22 +28748,15 @@ css /* scss */ `
|
|
|
28536
28748
|
height: 10000px;
|
|
28537
28749
|
background-color: ${SELECTION_BORDER_COLOR};
|
|
28538
28750
|
}
|
|
28539
|
-
.o-unhide {
|
|
28540
|
-
width:
|
|
28541
|
-
|
|
28542
|
-
|
|
28543
|
-
overflow: hidden;
|
|
28544
|
-
border-radius: 2px;
|
|
28545
|
-
top: calc(${HEADER_HEIGHT}px / 2 - ${UNHIDE_ICON_EDGE_LENGTH}px / 2);
|
|
28751
|
+
.o-unhide-buttons {
|
|
28752
|
+
width: fit-content;
|
|
28753
|
+
gap: 5px;
|
|
28754
|
+
transform: translate(-50%, 0);
|
|
28546
28755
|
}
|
|
28547
28756
|
.o-unhide:hover {
|
|
28548
28757
|
z-index: ${ComponentsImportance.Grid + 1};
|
|
28549
28758
|
background-color: lightgrey;
|
|
28550
28759
|
}
|
|
28551
|
-
.o-unhide > svg {
|
|
28552
|
-
position: relative;
|
|
28553
|
-
top: calc(${UNHIDE_ICON_EDGE_LENGTH}px / 2 - ${ICON_EDGE_LENGTH}px / 2);
|
|
28554
|
-
}
|
|
28555
28760
|
}
|
|
28556
28761
|
`;
|
|
28557
28762
|
AbstractResizer.props = {
|
|
@@ -28620,6 +28825,7 @@ class ColResizer extends AbstractResizer {
|
|
|
28620
28825
|
dimension: "COL",
|
|
28621
28826
|
base: this.state.base,
|
|
28622
28827
|
elements,
|
|
28828
|
+
position: this.state.position,
|
|
28623
28829
|
});
|
|
28624
28830
|
if (!result.isSuccessful && result.reasons.includes("WillRemoveExistingMerge" /* CommandResult.WillRemoveExistingMerge */)) {
|
|
28625
28831
|
this.env.raiseError(MergeErrorMessage);
|
|
@@ -28661,8 +28867,8 @@ class ColResizer extends AbstractResizer {
|
|
|
28661
28867
|
dimension: "COL",
|
|
28662
28868
|
});
|
|
28663
28869
|
}
|
|
28664
|
-
|
|
28665
|
-
return this._getDimensionsInViewport(hiddenIndex).start;
|
|
28870
|
+
getUnhideButtonStyle(hiddenIndex) {
|
|
28871
|
+
return cssPropertiesToCss({ left: this._getDimensionsInViewport(hiddenIndex).start + "px" });
|
|
28666
28872
|
}
|
|
28667
28873
|
}
|
|
28668
28874
|
css /* scss */ `
|
|
@@ -28708,18 +28914,9 @@ css /* scss */ `
|
|
|
28708
28914
|
height: 1px;
|
|
28709
28915
|
background-color: ${SELECTION_BORDER_COLOR};
|
|
28710
28916
|
}
|
|
28711
|
-
.o-unhide {
|
|
28712
|
-
|
|
28713
|
-
|
|
28714
|
-
position: absolute;
|
|
28715
|
-
overflow: hidden;
|
|
28716
|
-
border-radius: 2px;
|
|
28717
|
-
left: calc(${HEADER_WIDTH}px - ${UNHIDE_ICON_EDGE_LENGTH}px - 2px);
|
|
28718
|
-
}
|
|
28719
|
-
.o-unhide > svg {
|
|
28720
|
-
position: relative;
|
|
28721
|
-
left: calc(${UNHIDE_ICON_EDGE_LENGTH}px / 2 - ${ICON_EDGE_LENGTH}px / 2);
|
|
28722
|
-
top: calc(${UNHIDE_ICON_EDGE_LENGTH}px / 2 - ${ICON_EDGE_LENGTH}px / 2);
|
|
28917
|
+
.o-unhide-buttons {
|
|
28918
|
+
height: fit-content;
|
|
28919
|
+
transform: translate(0, -50%);
|
|
28723
28920
|
}
|
|
28724
28921
|
.o-unhide:hover {
|
|
28725
28922
|
z-index: ${ComponentsImportance.Grid + 1};
|
|
@@ -28793,6 +28990,7 @@ class RowResizer extends AbstractResizer {
|
|
|
28793
28990
|
dimension: "ROW",
|
|
28794
28991
|
base: this.state.base,
|
|
28795
28992
|
elements,
|
|
28993
|
+
position: this.state.position,
|
|
28796
28994
|
});
|
|
28797
28995
|
if (!result.isSuccessful && result.reasons.includes("WillRemoveExistingMerge" /* CommandResult.WillRemoveExistingMerge */)) {
|
|
28798
28996
|
this.env.raiseError(MergeErrorMessage);
|
|
@@ -28834,8 +29032,8 @@ class RowResizer extends AbstractResizer {
|
|
|
28834
29032
|
elements: hiddenElements,
|
|
28835
29033
|
});
|
|
28836
29034
|
}
|
|
28837
|
-
|
|
28838
|
-
return this._getDimensionsInViewport(hiddenIndex).start;
|
|
29035
|
+
getUnhideButtonStyle(hiddenIndex) {
|
|
29036
|
+
return cssPropertiesToCss({ top: this._getDimensionsInViewport(hiddenIndex).start + "px" });
|
|
28839
29037
|
}
|
|
28840
29038
|
}
|
|
28841
29039
|
css /* scss */ `
|
|
@@ -28900,8 +29098,8 @@ function useWheelHandler(handler) {
|
|
|
28900
29098
|
return val * (deltaMode === 0 ? 1 : DEFAULT_CELL_HEIGHT);
|
|
28901
29099
|
}
|
|
28902
29100
|
const onMouseWheel = (ev) => {
|
|
28903
|
-
const deltaX = normalize(ev.shiftKey ? ev.deltaY : ev.deltaX, ev.deltaMode);
|
|
28904
|
-
const deltaY = normalize(ev.shiftKey ? ev.deltaX : ev.deltaY, ev.deltaMode);
|
|
29101
|
+
const deltaX = normalize(ev.shiftKey && !isMacOS() ? ev.deltaY : ev.deltaX, ev.deltaMode);
|
|
29102
|
+
const deltaY = normalize(ev.shiftKey && !isMacOS() ? ev.deltaX : ev.deltaY, ev.deltaMode);
|
|
28905
29103
|
handler(deltaX, deltaY);
|
|
28906
29104
|
};
|
|
28907
29105
|
return onMouseWheel;
|
|
@@ -29342,7 +29540,6 @@ class Grid extends owl.Component {
|
|
|
29342
29540
|
owl.onMounted(() => this.focus());
|
|
29343
29541
|
this.props.exposeFocus(() => this.focus());
|
|
29344
29542
|
useGridDrawing("canvas", this.env.model, () => this.env.model.getters.getSheetViewDimensionWithHeaders());
|
|
29345
|
-
owl.useEffect(() => this.focus(), () => [this.env.model.getters.getActiveSheetId()]);
|
|
29346
29543
|
this.onMouseWheel = useWheelHandler((deltaX, deltaY) => {
|
|
29347
29544
|
this.moveCanvas(deltaX, deltaY);
|
|
29348
29545
|
this.hoveredCell.col = undefined;
|
|
@@ -29779,6 +29976,7 @@ class Grid extends owl.Component {
|
|
|
29779
29976
|
const content = clipboardData.getData(ClipboardMIMEType.PlainText);
|
|
29780
29977
|
const target = this.env.model.getters.getSelectedZones();
|
|
29781
29978
|
const clipboardString = this.env.model.getters.getClipboardTextContent();
|
|
29979
|
+
const isCutOperation = this.env.model.getters.isCutOperation();
|
|
29782
29980
|
if (clipboardString === content) {
|
|
29783
29981
|
// the paste actually comes from o-spreadsheet itself
|
|
29784
29982
|
interactivePaste(this.env, target);
|
|
@@ -29786,7 +29984,7 @@ class Grid extends owl.Component {
|
|
|
29786
29984
|
else {
|
|
29787
29985
|
interactivePasteFromOS(this.env, target, content);
|
|
29788
29986
|
}
|
|
29789
|
-
if (
|
|
29987
|
+
if (isCutOperation) {
|
|
29790
29988
|
await this.env.clipboard.write({ [ClipboardMIMEType.PlainText]: "" });
|
|
29791
29989
|
}
|
|
29792
29990
|
}
|
|
@@ -31399,12 +31597,6 @@ function convertChartData(chartData) {
|
|
|
31399
31597
|
}
|
|
31400
31598
|
function convertExcelRangeToSheetXC(range, dataSetsHaveTitle) {
|
|
31401
31599
|
let { sheetName, xc } = splitReference(range);
|
|
31402
|
-
if (sheetName) {
|
|
31403
|
-
sheetName = getCanonicalSheetName(sheetName) + "!";
|
|
31404
|
-
}
|
|
31405
|
-
else {
|
|
31406
|
-
sheetName = "";
|
|
31407
|
-
}
|
|
31408
31600
|
let zone = toUnboundedZone(xc);
|
|
31409
31601
|
if (dataSetsHaveTitle && zone.bottom !== undefined && zone.right !== undefined) {
|
|
31410
31602
|
const height = zone.bottom - zone.top + 1;
|
|
@@ -31417,7 +31609,7 @@ function convertExcelRangeToSheetXC(range, dataSetsHaveTitle) {
|
|
|
31417
31609
|
}
|
|
31418
31610
|
}
|
|
31419
31611
|
const dataXC = zoneToXc(zone);
|
|
31420
|
-
return sheetName
|
|
31612
|
+
return getFullReference(sheetName, dataXC);
|
|
31421
31613
|
}
|
|
31422
31614
|
|
|
31423
31615
|
/**
|
|
@@ -33344,7 +33536,7 @@ const machine = {
|
|
|
33344
33536
|
SPACE: goTo(State.RightRef),
|
|
33345
33537
|
NUMBER: goTo(State.Found),
|
|
33346
33538
|
REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
|
|
33347
|
-
SYMBOL: goTo(State.Found, (token) => isColHeader(token.value)),
|
|
33539
|
+
SYMBOL: goTo(State.Found, (token) => isColHeader(token.value) || isRowHeader(token.value)),
|
|
33348
33540
|
},
|
|
33349
33541
|
[State.RightColumnRef]: {
|
|
33350
33542
|
SPACE: goTo(State.RightColumnRef),
|
|
@@ -33355,6 +33547,7 @@ const machine = {
|
|
|
33355
33547
|
SPACE: goTo(State.RightRowRef),
|
|
33356
33548
|
NUMBER: goTo(State.Found),
|
|
33357
33549
|
REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
|
|
33550
|
+
SYMBOL: goTo(State.Found, (token) => isRowHeader(token.value)),
|
|
33358
33551
|
},
|
|
33359
33552
|
[State.Found]: {},
|
|
33360
33553
|
};
|
|
@@ -34080,6 +34273,14 @@ class BordersPlugin extends CorePlugin {
|
|
|
34080
34273
|
// ---------------------------------------------------------------------------
|
|
34081
34274
|
// Command Handling
|
|
34082
34275
|
// ---------------------------------------------------------------------------
|
|
34276
|
+
allowDispatch(cmd) {
|
|
34277
|
+
switch (cmd.type) {
|
|
34278
|
+
case "SET_BORDER":
|
|
34279
|
+
return this.checkBordersUnchanged(cmd);
|
|
34280
|
+
default:
|
|
34281
|
+
return "Success" /* CommandResult.Success */;
|
|
34282
|
+
}
|
|
34283
|
+
}
|
|
34083
34284
|
handle(cmd) {
|
|
34084
34285
|
switch (cmd.type) {
|
|
34085
34286
|
case "ADD_MERGE":
|
|
@@ -34499,6 +34700,14 @@ class BordersPlugin extends CorePlugin {
|
|
|
34499
34700
|
this.setBorders(sheetId, [{ ...zone, left: right }], "right", bordersTopLeft.right);
|
|
34500
34701
|
}
|
|
34501
34702
|
}
|
|
34703
|
+
checkBordersUnchanged(cmd) {
|
|
34704
|
+
const currentBorder = this.getCellBorder(cmd);
|
|
34705
|
+
const areAllNewBordersUndefined = !cmd.border?.bottom && !cmd.border?.left && !cmd.border?.right && !cmd.border?.top;
|
|
34706
|
+
if ((!currentBorder && areAllNewBordersUndefined) || deepEquals(currentBorder, cmd.border)) {
|
|
34707
|
+
return "NoChanges" /* CommandResult.NoChanges */;
|
|
34708
|
+
}
|
|
34709
|
+
return "Success" /* CommandResult.Success */;
|
|
34710
|
+
}
|
|
34502
34711
|
// ---------------------------------------------------------------------------
|
|
34503
34712
|
// Import/Export
|
|
34504
34713
|
// ---------------------------------------------------------------------------
|
|
@@ -35325,7 +35534,6 @@ class CellPlugin extends CorePlugin {
|
|
|
35325
35534
|
static getters = [
|
|
35326
35535
|
"zoneToXC",
|
|
35327
35536
|
"getCells",
|
|
35328
|
-
"getFormulaCellContent",
|
|
35329
35537
|
"getTranslatedCellFormula",
|
|
35330
35538
|
"getCellStyle",
|
|
35331
35539
|
"getCellById",
|
|
@@ -35354,8 +35562,9 @@ class CellPlugin extends CorePlugin {
|
|
|
35354
35562
|
allowDispatch(cmd) {
|
|
35355
35563
|
switch (cmd.type) {
|
|
35356
35564
|
case "UPDATE_CELL":
|
|
35565
|
+
return this.checkCellOutOfSheet(cmd);
|
|
35357
35566
|
case "CLEAR_CELL":
|
|
35358
|
-
return this.
|
|
35567
|
+
return this.checkValidations(cmd, this.chainValidations(this.checkCellOutOfSheet, this.checkUselessClearCell));
|
|
35359
35568
|
default:
|
|
35360
35569
|
return "Success" /* CommandResult.Success */;
|
|
35361
35570
|
}
|
|
@@ -35524,24 +35733,18 @@ class CellPlugin extends CorePlugin {
|
|
|
35524
35733
|
*/
|
|
35525
35734
|
getCellById(cellId) {
|
|
35526
35735
|
// this must be as fast as possible
|
|
35527
|
-
|
|
35528
|
-
|
|
35529
|
-
|
|
35530
|
-
if (cell) {
|
|
35531
|
-
return cell;
|
|
35532
|
-
}
|
|
35533
|
-
}
|
|
35534
|
-
return undefined;
|
|
35736
|
+
const position = this.getters.getCellPosition(cellId);
|
|
35737
|
+
const sheet = this.cells[position.sheetId];
|
|
35738
|
+
return sheet[cellId];
|
|
35535
35739
|
}
|
|
35536
35740
|
/*
|
|
35537
35741
|
* Reconstructs the original formula string based on a normalized form and its dependencies
|
|
35538
35742
|
*/
|
|
35539
35743
|
getFormulaCellContent(sheetId, compiledFormula, dependencies) {
|
|
35540
|
-
const ranges = dependencies || compiledFormula.dependencies;
|
|
35541
35744
|
let rangeIndex = 0;
|
|
35542
35745
|
return concat(compiledFormula.tokens.map((token) => {
|
|
35543
35746
|
if (token.type === "REFERENCE") {
|
|
35544
|
-
const range =
|
|
35747
|
+
const range = dependencies[rangeIndex++];
|
|
35545
35748
|
return this.getters.getRangeString(range, sheetId);
|
|
35546
35749
|
}
|
|
35547
35750
|
return token.value;
|
|
@@ -35762,13 +35965,23 @@ class CellPlugin extends CorePlugin {
|
|
|
35762
35965
|
},
|
|
35763
35966
|
};
|
|
35764
35967
|
}
|
|
35765
|
-
checkCellOutOfSheet(
|
|
35968
|
+
checkCellOutOfSheet(cmd) {
|
|
35969
|
+
const { sheetId, col, row } = cmd;
|
|
35766
35970
|
const sheet = this.getters.tryGetSheet(sheetId);
|
|
35767
35971
|
if (!sheet)
|
|
35768
35972
|
return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
|
|
35769
35973
|
const sheetZone = this.getters.getSheetZone(sheetId);
|
|
35770
35974
|
return isInside(col, row, sheetZone) ? "Success" /* CommandResult.Success */ : "TargetOutOfSheet" /* CommandResult.TargetOutOfSheet */;
|
|
35771
35975
|
}
|
|
35976
|
+
checkUselessClearCell(cmd) {
|
|
35977
|
+
const cell = this.getters.getCell(cmd);
|
|
35978
|
+
if (!cell)
|
|
35979
|
+
return "NoChanges" /* CommandResult.NoChanges */;
|
|
35980
|
+
if (!cell.content && !cell.style && !cell.format) {
|
|
35981
|
+
return "NoChanges" /* CommandResult.NoChanges */;
|
|
35982
|
+
}
|
|
35983
|
+
return "Success" /* CommandResult.Success */;
|
|
35984
|
+
}
|
|
35772
35985
|
}
|
|
35773
35986
|
class FormulaCellWithDependencies {
|
|
35774
35987
|
id;
|
|
@@ -36458,6 +36671,9 @@ class DataValidationPlugin extends CorePlugin {
|
|
|
36458
36671
|
return this.rules[sheetId].find((rule) => rule.id === id);
|
|
36459
36672
|
}
|
|
36460
36673
|
getValidationRuleForCell({ sheetId, col, row }) {
|
|
36674
|
+
if (!this.rules[sheetId]) {
|
|
36675
|
+
return undefined;
|
|
36676
|
+
}
|
|
36461
36677
|
for (const rule of this.rules[sheetId]) {
|
|
36462
36678
|
for (const range of rule.ranges) {
|
|
36463
36679
|
if (isInside(col, row, range.zone)) {
|
|
@@ -37311,7 +37527,16 @@ class HeaderVisibilityPlugin extends CorePlugin {
|
|
|
37311
37527
|
return consecutiveIndexes;
|
|
37312
37528
|
}
|
|
37313
37529
|
getAllVisibleHeaders(sheetId, dimension) {
|
|
37314
|
-
|
|
37530
|
+
const headers = range(0, this.getters.getNumberHeaders(sheetId, dimension));
|
|
37531
|
+
const foldedHeaders = [];
|
|
37532
|
+
this.getters.getHeaderGroups(sheetId, dimension).forEach((group) => {
|
|
37533
|
+
if (group.isFolded) {
|
|
37534
|
+
foldedHeaders.push(...range(group.start, group.end + 1));
|
|
37535
|
+
}
|
|
37536
|
+
});
|
|
37537
|
+
return headers.filter((i) => {
|
|
37538
|
+
return !this.hiddenHeaders[sheetId][dimension][i] && !foldedHeaders.includes(i);
|
|
37539
|
+
});
|
|
37315
37540
|
}
|
|
37316
37541
|
import(data) {
|
|
37317
37542
|
for (let sheet of data.sheets) {
|
|
@@ -37630,7 +37855,7 @@ class MergePlugin extends CorePlugin {
|
|
|
37630
37855
|
const rangeString = this.getters.getRangeString(expandedRange, forSheetId);
|
|
37631
37856
|
if (this.isSingleCellOrMerge(rangeImpl.sheetId, rangeImpl.zone)) {
|
|
37632
37857
|
const { sheetName, xc } = splitReference(rangeString);
|
|
37633
|
-
return
|
|
37858
|
+
return getFullReference(sheetName, xc.split(":")[0]);
|
|
37634
37859
|
}
|
|
37635
37860
|
return rangeString;
|
|
37636
37861
|
}
|
|
@@ -39055,10 +39280,13 @@ class SheetPlugin extends CorePlugin {
|
|
|
39055
39280
|
// begin with the end.
|
|
39056
39281
|
rows.sort((a, b) => b - a);
|
|
39057
39282
|
for (let group of groupConsecutive(rows)) {
|
|
39283
|
+
// indexes are sorted in the descending order
|
|
39284
|
+
const from = group[group.length - 1];
|
|
39285
|
+
const to = group[0];
|
|
39058
39286
|
// Move the cells.
|
|
39059
|
-
this.moveCellOnRowsDeletion(sheet,
|
|
39060
|
-
// Effectively delete the
|
|
39061
|
-
|
|
39287
|
+
this.moveCellOnRowsDeletion(sheet, from, to);
|
|
39288
|
+
// Effectively delete the rows
|
|
39289
|
+
this.updateRowsStructureOnDeletion(sheet, from, to);
|
|
39062
39290
|
}
|
|
39063
39291
|
const count = rows.filter((row) => row < sheet.panes.ySplit).length;
|
|
39064
39292
|
if (count) {
|
|
@@ -39080,8 +39308,6 @@ class SheetPlugin extends CorePlugin {
|
|
|
39080
39308
|
this.addEmptyRows(sheet, quantity);
|
|
39081
39309
|
// Move the cells.
|
|
39082
39310
|
this.moveCellsOnAddition(sheet, index, quantity, "rows");
|
|
39083
|
-
// Recompute the left-right/top-bottom.
|
|
39084
|
-
this.updateRowsStructureOnAddition(sheet, row, quantity);
|
|
39085
39311
|
if (index < sheet.panes.ySplit) {
|
|
39086
39312
|
this.setPaneDivisions(sheet.id, sheet.panes.ySplit + quantity, "ROW");
|
|
39087
39313
|
}
|
|
@@ -39182,35 +39408,20 @@ class SheetPlugin extends CorePlugin {
|
|
|
39182
39408
|
}
|
|
39183
39409
|
}
|
|
39184
39410
|
}
|
|
39185
|
-
updateRowsStructureOnDeletion(
|
|
39411
|
+
updateRowsStructureOnDeletion(sheet, deleteFromRow, deleteToRow) {
|
|
39186
39412
|
const rows = [];
|
|
39187
|
-
const cellsQueue = sheet.rows.map((row) => row.cells);
|
|
39413
|
+
const cellsQueue = sheet.rows.map((row) => row.cells).reverse();
|
|
39188
39414
|
for (let i in sheet.rows) {
|
|
39189
|
-
|
|
39415
|
+
const row = Number(i);
|
|
39416
|
+
if (row >= deleteFromRow && row <= deleteToRow) {
|
|
39190
39417
|
continue;
|
|
39191
39418
|
}
|
|
39192
39419
|
rows.push({
|
|
39193
|
-
cells: cellsQueue.
|
|
39420
|
+
cells: cellsQueue.pop(),
|
|
39194
39421
|
});
|
|
39195
39422
|
}
|
|
39196
39423
|
this.history.update("sheets", sheet.id, "rows", rows);
|
|
39197
39424
|
}
|
|
39198
|
-
/**
|
|
39199
|
-
* Update the rows of the sheet after an addition:
|
|
39200
|
-
* - Rename the rows
|
|
39201
|
-
*
|
|
39202
|
-
* @param sheet Sheet on which the deletion occurs
|
|
39203
|
-
* @param addedRow Index of the added row
|
|
39204
|
-
* @param rowsToAdd Number of the rows to add
|
|
39205
|
-
*/
|
|
39206
|
-
updateRowsStructureOnAddition(sheet, addedRow, rowsToAdd) {
|
|
39207
|
-
const rows = [];
|
|
39208
|
-
const cellsQueue = sheet.rows.map((row) => row.cells);
|
|
39209
|
-
sheet.rows.forEach(() => rows.push({
|
|
39210
|
-
cells: cellsQueue.shift(),
|
|
39211
|
-
}));
|
|
39212
|
-
this.history.update("sheets", sheet.id, "rows", rows);
|
|
39213
|
-
}
|
|
39214
39425
|
/**
|
|
39215
39426
|
* Add empty rows at the end of the rows
|
|
39216
39427
|
*
|
|
@@ -39737,6 +39948,7 @@ class CompilationParametersBuilder {
|
|
|
39737
39948
|
getters;
|
|
39738
39949
|
computeCell;
|
|
39739
39950
|
evalContext;
|
|
39951
|
+
rangeCache = {};
|
|
39740
39952
|
constructor(context, getters, computeCell) {
|
|
39741
39953
|
this.getters = getters;
|
|
39742
39954
|
this.computeCell = computeCell;
|
|
@@ -39759,7 +39971,8 @@ class CompilationParametersBuilder {
|
|
|
39759
39971
|
refFn(range, isMeta, functionName, paramNumber) {
|
|
39760
39972
|
if (isMeta) {
|
|
39761
39973
|
// Use zoneToXc of zone instead of getRangeString to avoid sending unbounded ranges
|
|
39762
|
-
|
|
39974
|
+
const sheetName = this.getters.getSheetName(range.sheetId);
|
|
39975
|
+
return { value: getFullReference(sheetName, zoneToXc(range.zone)) };
|
|
39763
39976
|
}
|
|
39764
39977
|
if (!isZoneValid(range.zone)) {
|
|
39765
39978
|
throw new InvalidReferenceError();
|
|
@@ -39784,10 +39997,13 @@ class CompilationParametersBuilder {
|
|
|
39784
39997
|
if (evaluatedCell === undefined) {
|
|
39785
39998
|
return { value: null, format: this.getters.getCell(position)?.format };
|
|
39786
39999
|
}
|
|
40000
|
+
if (evaluatedCell.type === CellValueType.error) {
|
|
40001
|
+
throw evaluatedCell.error;
|
|
40002
|
+
}
|
|
39787
40003
|
return evaluatedCell;
|
|
39788
40004
|
}
|
|
39789
40005
|
getEvaluatedCellIfNotEmpty(position) {
|
|
39790
|
-
const evaluatedCell = this.
|
|
40006
|
+
const evaluatedCell = this.computeCell(position);
|
|
39791
40007
|
if (evaluatedCell.type === CellValueType.empty) {
|
|
39792
40008
|
const cell = this.getters.getCell(position);
|
|
39793
40009
|
if (!cell || (!cell.isFormula && cell.content === "")) {
|
|
@@ -39796,13 +40012,6 @@ class CompilationParametersBuilder {
|
|
|
39796
40012
|
}
|
|
39797
40013
|
return evaluatedCell;
|
|
39798
40014
|
}
|
|
39799
|
-
getEvaluatedCell(position) {
|
|
39800
|
-
const evaluatedCell = this.computeCell(position);
|
|
39801
|
-
if (evaluatedCell.type === CellValueType.error) {
|
|
39802
|
-
throw evaluatedCell.error;
|
|
39803
|
-
}
|
|
39804
|
-
return evaluatedCell;
|
|
39805
|
-
}
|
|
39806
40015
|
/**
|
|
39807
40016
|
* Return the values of the cell(s) used in reference, but always in the format of a range even
|
|
39808
40017
|
* if a single cell is referenced. It is a list of col values. This is useful for the formulas that describe parameters as
|
|
@@ -39822,17 +40031,33 @@ class CompilationParametersBuilder {
|
|
|
39822
40031
|
if (!_zone) {
|
|
39823
40032
|
return [[]];
|
|
39824
40033
|
}
|
|
40034
|
+
const { top, left, bottom, right } = zone;
|
|
40035
|
+
const cacheKey = `${sheetId}-${top}-${left}-${bottom}-${right}`;
|
|
40036
|
+
if (cacheKey in this.rangeCache) {
|
|
40037
|
+
const result = this.rangeCache[cacheKey];
|
|
40038
|
+
if (result instanceof EvaluationError) {
|
|
40039
|
+
throw result;
|
|
40040
|
+
}
|
|
40041
|
+
return result;
|
|
40042
|
+
}
|
|
39825
40043
|
const height = _zone.bottom - _zone.top + 1;
|
|
39826
40044
|
const width = _zone.right - _zone.left + 1;
|
|
39827
|
-
const matrix = Array
|
|
40045
|
+
const matrix = new Array(width);
|
|
39828
40046
|
// Performance issue: nested loop is faster than a map here
|
|
39829
40047
|
for (let col = _zone.left; col <= _zone.right; col++) {
|
|
40048
|
+
const colIndex = col - _zone.left;
|
|
40049
|
+
matrix[colIndex] = new Array(height);
|
|
39830
40050
|
for (let row = _zone.top; row <= _zone.bottom; row++) {
|
|
39831
|
-
const
|
|
40051
|
+
const evaluatedCell = this.getEvaluatedCellIfNotEmpty({ sheetId, col, row });
|
|
40052
|
+
if (evaluatedCell?.type === CellValueType.error) {
|
|
40053
|
+
this.rangeCache[cacheKey] = evaluatedCell.error;
|
|
40054
|
+
throw evaluatedCell.error;
|
|
40055
|
+
}
|
|
39832
40056
|
const rowIndex = row - _zone.top;
|
|
39833
40057
|
matrix[colIndex][rowIndex] = this.readCell({ sheetId, col, row });
|
|
39834
40058
|
}
|
|
39835
40059
|
}
|
|
40060
|
+
this.rangeCache[cacheKey] = matrix;
|
|
39836
40061
|
return matrix;
|
|
39837
40062
|
}
|
|
39838
40063
|
}
|
|
@@ -40038,6 +40263,7 @@ class Evaluator {
|
|
|
40038
40263
|
this.formulaDependencies().addDependencies(positionId, dependencies);
|
|
40039
40264
|
}
|
|
40040
40265
|
updateCompilationParameters() {
|
|
40266
|
+
// rebuild the compilation parameters (with a clean cache)
|
|
40041
40267
|
this.compilationParams = buildCompilationParameters(this.context, this.getters, this.computeAndSave.bind(this));
|
|
40042
40268
|
}
|
|
40043
40269
|
evaluateCells(positions) {
|
|
@@ -40081,6 +40307,16 @@ class Evaluator {
|
|
|
40081
40307
|
this.evaluatedCells = new Map();
|
|
40082
40308
|
this.evaluate(this.getAllCells());
|
|
40083
40309
|
}
|
|
40310
|
+
evaluateFormula(sheetId, formulaString) {
|
|
40311
|
+
const compiledFormula = compile(formulaString);
|
|
40312
|
+
const ranges = compiledFormula.dependencies.map((xc) => this.getters.getRangeFromSheetXC(sheetId, xc));
|
|
40313
|
+
this.updateCompilationParameters();
|
|
40314
|
+
const result = updateEvalContextAndExecute({ ...compiledFormula, dependencies: ranges }, this.compilationParams, sheetId);
|
|
40315
|
+
if (isMatrix(result)) {
|
|
40316
|
+
return matrixMap(result, (cell) => cell.value);
|
|
40317
|
+
}
|
|
40318
|
+
return result.value;
|
|
40319
|
+
}
|
|
40084
40320
|
getAllCells() {
|
|
40085
40321
|
const positionIds = new JetSet();
|
|
40086
40322
|
for (const sheetId of this.getters.getSheetIds()) {
|
|
@@ -40107,6 +40343,7 @@ class Evaluator {
|
|
|
40107
40343
|
this.nextPositionsToUpdate = cells;
|
|
40108
40344
|
let currentIteration = 0;
|
|
40109
40345
|
while (this.nextPositionsToUpdate.size && currentIteration++ < MAX_ITERATION) {
|
|
40346
|
+
this.updateCompilationParameters();
|
|
40110
40347
|
const positionIds = Array.from(this.nextPositionsToUpdate);
|
|
40111
40348
|
this.nextPositionsToUpdate.clear();
|
|
40112
40349
|
for (let i = 0; i < positionIds.length; ++i) {
|
|
@@ -40130,7 +40367,8 @@ class Evaluator {
|
|
|
40130
40367
|
if (!this.blockedArrayFormulas.has(positionId)) {
|
|
40131
40368
|
this.invalidateSpreading(positionId);
|
|
40132
40369
|
}
|
|
40133
|
-
const
|
|
40370
|
+
const cellPosition = this.decodePosition(positionId);
|
|
40371
|
+
const cell = this.getters.getCell(cellPosition);
|
|
40134
40372
|
if (cell === undefined) {
|
|
40135
40373
|
return createEvaluatedCell("", { locale: this.getters.getLocale() });
|
|
40136
40374
|
}
|
|
@@ -40141,7 +40379,7 @@ class Evaluator {
|
|
|
40141
40379
|
}
|
|
40142
40380
|
this.cellsBeingComputed.add(cellId);
|
|
40143
40381
|
return cell.isFormula
|
|
40144
|
-
? this.computeFormulaCell(cell)
|
|
40382
|
+
? this.computeFormulaCell(cellPosition.sheetId, cell)
|
|
40145
40383
|
: evaluateLiteral(cell.content, { format: cell.format, locale: this.getters.getLocale() });
|
|
40146
40384
|
}
|
|
40147
40385
|
catch (e) {
|
|
@@ -40167,14 +40405,9 @@ class Evaluator {
|
|
|
40167
40405
|
e.message = e.message.replace("[[FUNCTION_NAME]]", __lastFnCalled);
|
|
40168
40406
|
return errorCell(e);
|
|
40169
40407
|
}
|
|
40170
|
-
computeFormulaCell(cellData) {
|
|
40408
|
+
computeFormulaCell(sheetId, cellData) {
|
|
40171
40409
|
const cellId = cellData.id;
|
|
40172
|
-
this.compilationParams
|
|
40173
|
-
// compute the value lazily for performance reasons
|
|
40174
|
-
const position = this.compilationParams[2].getters.getCellPosition(cellId);
|
|
40175
|
-
return toXC(position.col, position.row);
|
|
40176
|
-
};
|
|
40177
|
-
const formulaReturn = cellData.compiledFormula.execute(cellData.compiledFormula.dependencies, ...this.compilationParams);
|
|
40410
|
+
const formulaReturn = updateEvalContextAndExecute(cellData.compiledFormula, this.compilationParams, sheetId, cellId);
|
|
40178
40411
|
if (!isMatrix(formulaReturn)) {
|
|
40179
40412
|
return createEvaluatedCell(formulaReturn.value, {
|
|
40180
40413
|
format: cellData.format || formulaReturn.format,
|
|
@@ -40376,6 +40609,18 @@ class PositionBitsEncoder {
|
|
|
40376
40609
|
return sheetId;
|
|
40377
40610
|
}
|
|
40378
40611
|
}
|
|
40612
|
+
function updateEvalContextAndExecute(compiledFormula, compilationParams, sheetId, cellId) {
|
|
40613
|
+
compilationParams[2].__originCellXC = lazy(() => {
|
|
40614
|
+
if (!cellId) {
|
|
40615
|
+
return undefined;
|
|
40616
|
+
}
|
|
40617
|
+
// compute the value lazily for performance reasons
|
|
40618
|
+
const position = compilationParams[2].getters.getCellPosition(cellId);
|
|
40619
|
+
return toXC(position.col, position.row);
|
|
40620
|
+
});
|
|
40621
|
+
compilationParams[2].__originSheetId = sheetId;
|
|
40622
|
+
return compiledFormula.execute(compiledFormula.dependencies, ...compilationParams);
|
|
40623
|
+
}
|
|
40379
40624
|
|
|
40380
40625
|
//#region
|
|
40381
40626
|
// ---------------------------------------------------------------------------
|
|
@@ -40470,7 +40715,6 @@ class PositionBitsEncoder {
|
|
|
40470
40715
|
// of other cells depending on it, at the next iteration.
|
|
40471
40716
|
//#endregion
|
|
40472
40717
|
class EvaluationPlugin extends UIPlugin {
|
|
40473
|
-
config;
|
|
40474
40718
|
static getters = [
|
|
40475
40719
|
"evaluateFormula",
|
|
40476
40720
|
"getCorrespondingFormulaCell",
|
|
@@ -40481,15 +40725,13 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
40481
40725
|
"getEvaluatedCells",
|
|
40482
40726
|
"getEvaluatedCellsInZone",
|
|
40483
40727
|
"getSpreadPositionsOf",
|
|
40728
|
+
"getArrayFormulaSpreadingOn",
|
|
40484
40729
|
];
|
|
40485
40730
|
shouldRebuildDependenciesGraph = true;
|
|
40486
40731
|
evaluator;
|
|
40487
|
-
compilationParams;
|
|
40488
40732
|
positionsToUpdate = [];
|
|
40489
40733
|
constructor(config) {
|
|
40490
40734
|
super(config);
|
|
40491
|
-
this.config = config;
|
|
40492
|
-
this.compilationParams = this.getCompilationParameters();
|
|
40493
40735
|
this.evaluator = new Evaluator(config.custom, this.getters);
|
|
40494
40736
|
}
|
|
40495
40737
|
// ---------------------------------------------------------------------------
|
|
@@ -40514,10 +40756,6 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
40514
40756
|
case "EVALUATE_CELLS":
|
|
40515
40757
|
this.evaluator.evaluateAllCells();
|
|
40516
40758
|
break;
|
|
40517
|
-
case "UPDATE_LOCALE":
|
|
40518
|
-
this.compilationParams = this.getCompilationParameters();
|
|
40519
|
-
this.evaluator.updateCompilationParameters();
|
|
40520
|
-
break;
|
|
40521
40759
|
}
|
|
40522
40760
|
}
|
|
40523
40761
|
finalize() {
|
|
@@ -40535,16 +40773,7 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
40535
40773
|
// Getters
|
|
40536
40774
|
// ---------------------------------------------------------------------------
|
|
40537
40775
|
evaluateFormula(sheetId, formulaString) {
|
|
40538
|
-
|
|
40539
|
-
const ranges = [];
|
|
40540
|
-
for (let xc of compiledFormula.dependencies) {
|
|
40541
|
-
ranges.push(this.getters.getRangeFromSheetXC(sheetId, xc));
|
|
40542
|
-
}
|
|
40543
|
-
const array = compiledFormula.execute(ranges, ...this.compilationParams);
|
|
40544
|
-
if (isMatrix(array)) {
|
|
40545
|
-
return array.map((col) => col.map((row) => row.value));
|
|
40546
|
-
}
|
|
40547
|
-
return array.value;
|
|
40776
|
+
return this.evaluator.evaluateFormula(sheetId, formulaString);
|
|
40548
40777
|
}
|
|
40549
40778
|
/**
|
|
40550
40779
|
* Return the value of each cell in the range as they are displayed in the grid.
|
|
@@ -40593,6 +40822,9 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
40593
40822
|
getSpreadPositionsOf(position) {
|
|
40594
40823
|
return this.evaluator.getSpreadPositionsOf(position);
|
|
40595
40824
|
}
|
|
40825
|
+
getArrayFormulaSpreadingOn(position) {
|
|
40826
|
+
return this.evaluator.getArrayFormulaSpreadingOn(position);
|
|
40827
|
+
}
|
|
40596
40828
|
// ---------------------------------------------------------------------------
|
|
40597
40829
|
// Export
|
|
40598
40830
|
// ---------------------------------------------------------------------------
|
|
@@ -40636,7 +40868,7 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
40636
40868
|
else if (cell && cell.content) {
|
|
40637
40869
|
return undefined;
|
|
40638
40870
|
}
|
|
40639
|
-
const spreadingFormulaPosition = this.
|
|
40871
|
+
const spreadingFormulaPosition = this.getArrayFormulaSpreadingOn(position);
|
|
40640
40872
|
if (spreadingFormulaPosition === undefined) {
|
|
40641
40873
|
return undefined;
|
|
40642
40874
|
}
|
|
@@ -40646,9 +40878,6 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
40646
40878
|
}
|
|
40647
40879
|
return undefined;
|
|
40648
40880
|
}
|
|
40649
|
-
getCompilationParameters() {
|
|
40650
|
-
return buildCompilationParameters(this.config.custom, this.getters, (position) => this.evaluator.getEvaluatedCell(position));
|
|
40651
|
-
}
|
|
40652
40881
|
}
|
|
40653
40882
|
function isBadExpression(tokens) {
|
|
40654
40883
|
try {
|
|
@@ -40925,7 +41154,7 @@ class EvaluationConditionalFormatPlugin extends UIPlugin {
|
|
|
40925
41154
|
// ---------------------------------------------------------------------------
|
|
40926
41155
|
handle(cmd) {
|
|
40927
41156
|
if (invalidateCFEvaluationCommands.has(cmd.type) ||
|
|
40928
|
-
(cmd.type === "UPDATE_CELL" && "content" in cmd)) {
|
|
41157
|
+
(cmd.type === "UPDATE_CELL" && ("content" in cmd || "format" in cmd))) {
|
|
40929
41158
|
this.isStale = true;
|
|
40930
41159
|
}
|
|
40931
41160
|
}
|
|
@@ -41251,7 +41480,7 @@ class EvaluationDataValidationPlugin extends UIPlugin {
|
|
|
41251
41480
|
handle(cmd) {
|
|
41252
41481
|
if (invalidateEvaluationCommands.has(cmd.type) ||
|
|
41253
41482
|
cmd.type === "EVALUATE_CELLS" ||
|
|
41254
|
-
(cmd.type === "UPDATE_CELL" && "content" in cmd)) {
|
|
41483
|
+
(cmd.type === "UPDATE_CELL" && ("content" in cmd || "format" in cmd))) {
|
|
41255
41484
|
this.validationResults = {};
|
|
41256
41485
|
return;
|
|
41257
41486
|
}
|
|
@@ -41789,19 +42018,21 @@ class AutofillPlugin extends UIPlugin {
|
|
|
41789
42018
|
let col = zone.left;
|
|
41790
42019
|
let row = zone.bottom;
|
|
41791
42020
|
if (col > 0) {
|
|
41792
|
-
let
|
|
41793
|
-
while (
|
|
42021
|
+
let leftPosition = { sheetId, col: col - 1, row };
|
|
42022
|
+
while (this.getters.getEvaluatedCell(leftPosition).type !== CellValueType.empty ||
|
|
42023
|
+
this.getters.getCell(leftPosition)?.content) {
|
|
41794
42024
|
row += 1;
|
|
41795
|
-
|
|
42025
|
+
leftPosition = { sheetId, col: col - 1, row };
|
|
41796
42026
|
}
|
|
41797
42027
|
}
|
|
41798
42028
|
if (row === zone.bottom) {
|
|
41799
42029
|
col = zone.right;
|
|
41800
42030
|
if (col <= this.getters.getNumberCols(sheetId)) {
|
|
41801
|
-
let
|
|
41802
|
-
while (
|
|
42031
|
+
let rightPosition = { sheetId, col: col + 1, row };
|
|
42032
|
+
while (this.getters.getEvaluatedCell(rightPosition).type !== CellValueType.empty ||
|
|
42033
|
+
this.getters.getCell(rightPosition)?.content) {
|
|
41803
42034
|
row += 1;
|
|
41804
|
-
|
|
42035
|
+
rightPosition = { sheetId, col: col + 1, row };
|
|
41805
42036
|
}
|
|
41806
42037
|
}
|
|
41807
42038
|
}
|
|
@@ -42793,6 +43024,7 @@ class Session extends EventBus {
|
|
|
42793
43024
|
isReplayingInitialRevisions = false;
|
|
42794
43025
|
processedRevisions = new Set();
|
|
42795
43026
|
uuidGenerator = new UuidGenerator();
|
|
43027
|
+
lastLocalOperation;
|
|
42796
43028
|
/**
|
|
42797
43029
|
* Manages the collaboration between multiple users on the same spreadsheet.
|
|
42798
43030
|
* It can forward local state changes to other users to ensure they all eventually
|
|
@@ -42825,6 +43057,11 @@ class Session extends EventBus {
|
|
|
42825
43057
|
return;
|
|
42826
43058
|
const revision = new Revision(this.uuidGenerator.uuidv4(), this.clientId, commands, rootCommand, changes, Date.now());
|
|
42827
43059
|
this.revisions.append(revision.id, revision);
|
|
43060
|
+
// REQUEST_REDO just repeats the last operation, the
|
|
43061
|
+
// last operation is still the same and should not change.
|
|
43062
|
+
if (rootCommand.type !== "REQUEST_REDO") {
|
|
43063
|
+
this.lastLocalOperation = revision;
|
|
43064
|
+
}
|
|
42828
43065
|
this.trigger("new-local-state-update", { id: revision.id });
|
|
42829
43066
|
this.sendUpdateMessage({
|
|
42830
43067
|
type: "REMOTE_REVISION",
|
|
@@ -42921,19 +43158,10 @@ class Session extends EventBus {
|
|
|
42921
43158
|
return this.pendingMessages.length === 0;
|
|
42922
43159
|
}
|
|
42923
43160
|
/**
|
|
42924
|
-
* Get the last local revision
|
|
43161
|
+
* Get the last local revision
|
|
42925
43162
|
* */
|
|
42926
|
-
getLastLocalNonEmptyRevision(
|
|
42927
|
-
|
|
42928
|
-
for (const rev of revisions) {
|
|
42929
|
-
if (rev.rootCommand === "SNAPSHOT")
|
|
42930
|
-
return undefined;
|
|
42931
|
-
if (!rev.rootCommand || rev.rootCommand === "REMOTE")
|
|
42932
|
-
continue;
|
|
42933
|
-
if (!ignoredRootCommands.includes(rev.rootCommand?.type) && rev.commands.length)
|
|
42934
|
-
return rev;
|
|
42935
|
-
}
|
|
42936
|
-
return undefined;
|
|
43163
|
+
getLastLocalNonEmptyRevision() {
|
|
43164
|
+
return this.lastLocalOperation;
|
|
42937
43165
|
}
|
|
42938
43166
|
_move(position) {
|
|
42939
43167
|
// this method is debounced and might be called after the client
|
|
@@ -42993,7 +43221,7 @@ class Session extends EventBus {
|
|
|
42993
43221
|
break;
|
|
42994
43222
|
case "REMOTE_REVISION":
|
|
42995
43223
|
const { clientId, commands, timestamp } = message;
|
|
42996
|
-
const revision = new Revision(message.nextRevisionId, clientId, commands,
|
|
43224
|
+
const revision = new Revision(message.nextRevisionId, clientId, commands, undefined, undefined, timestamp);
|
|
42997
43225
|
if (revision.clientId !== this.clientId) {
|
|
42998
43226
|
this.revisions.insert(revision.id, revision, message.serverRevisionId);
|
|
42999
43227
|
const pendingCommands = this.pendingMessages
|
|
@@ -43006,10 +43234,11 @@ class Session extends EventBus {
|
|
|
43006
43234
|
}
|
|
43007
43235
|
break;
|
|
43008
43236
|
case "SNAPSHOT_CREATED": {
|
|
43009
|
-
const revision = new Revision(message.nextRevisionId, "server", [],
|
|
43237
|
+
const revision = new Revision(message.nextRevisionId, "server", [], undefined, undefined, Date.now());
|
|
43010
43238
|
this.revisions.insert(revision.id, revision, message.serverRevisionId);
|
|
43011
43239
|
this.dropPendingHistoryMessages();
|
|
43012
43240
|
this.trigger("snapshot");
|
|
43241
|
+
this.lastLocalOperation = undefined;
|
|
43013
43242
|
break;
|
|
43014
43243
|
}
|
|
43015
43244
|
}
|
|
@@ -43347,11 +43576,26 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
|
|
|
43347
43576
|
let cellsInRow = [];
|
|
43348
43577
|
for (let col of columnsIndex) {
|
|
43349
43578
|
const position = { col, row, sheetId };
|
|
43579
|
+
const spreader = getters.getArrayFormulaSpreadingOn(position);
|
|
43580
|
+
let cell = getters.getCell(position);
|
|
43581
|
+
const evaluatedCell = getters.getEvaluatedCell(position);
|
|
43582
|
+
if (spreader) {
|
|
43583
|
+
const isSpreaderCopied = rowsIndex.includes(spreader.row) && columnsIndex.includes(spreader.col);
|
|
43584
|
+
const content = isSpreaderCopied
|
|
43585
|
+
? ""
|
|
43586
|
+
: formatValue(evaluatedCell.value, { locale: getters.getLocale() });
|
|
43587
|
+
cell = {
|
|
43588
|
+
id: cell?.id || "",
|
|
43589
|
+
style: cell?.style,
|
|
43590
|
+
format: evaluatedCell.format,
|
|
43591
|
+
content,
|
|
43592
|
+
isFormula: false,
|
|
43593
|
+
};
|
|
43594
|
+
}
|
|
43350
43595
|
cellsInRow.push({
|
|
43351
|
-
cell
|
|
43352
|
-
style: getters.getCellComputedStyle(position),
|
|
43353
|
-
evaluatedCell: getters.getEvaluatedCell(position),
|
|
43596
|
+
cell,
|
|
43354
43597
|
border: getters.getCellBorder(position) || undefined,
|
|
43598
|
+
evaluatedCell,
|
|
43355
43599
|
position,
|
|
43356
43600
|
});
|
|
43357
43601
|
}
|
|
@@ -43473,13 +43717,6 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
|
|
|
43473
43717
|
});
|
|
43474
43718
|
}
|
|
43475
43719
|
this.pasteCopiedTables(target);
|
|
43476
|
-
this.cells.forEach((row) => {
|
|
43477
|
-
row.forEach((c) => {
|
|
43478
|
-
if (c.cell) {
|
|
43479
|
-
c.cell = undefined;
|
|
43480
|
-
}
|
|
43481
|
-
});
|
|
43482
|
-
});
|
|
43483
43720
|
}
|
|
43484
43721
|
/**
|
|
43485
43722
|
* The clipped zone is copied as many times as it fits in the target.
|
|
@@ -43553,7 +43790,7 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
|
|
|
43553
43790
|
clearClippedZones() {
|
|
43554
43791
|
for (const row of this.cells) {
|
|
43555
43792
|
for (const cell of row) {
|
|
43556
|
-
if (cell
|
|
43793
|
+
if (cell?.cell) {
|
|
43557
43794
|
this.dispatch("CLEAR_CELL", cell.position);
|
|
43558
43795
|
}
|
|
43559
43796
|
}
|
|
@@ -43579,6 +43816,9 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
|
|
|
43579
43816
|
const rowCells = this.cells[r];
|
|
43580
43817
|
for (let c = 0; c < width; c++) {
|
|
43581
43818
|
const origin = rowCells[c];
|
|
43819
|
+
if (!origin) {
|
|
43820
|
+
continue;
|
|
43821
|
+
}
|
|
43582
43822
|
const position = { col: col + c, row: row + r, sheetId: sheetId };
|
|
43583
43823
|
// TODO: refactor this part. the "Paste merge" action is also executed with
|
|
43584
43824
|
// MOVE_RANGES in pasteFromCut. Adding a condition on the operation type here
|
|
@@ -43602,53 +43842,42 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
|
|
|
43602
43842
|
pasteCell(origin, target, operation, clipboardOption) {
|
|
43603
43843
|
const { sheetId, col, row } = target;
|
|
43604
43844
|
const targetCell = this.getters.getEvaluatedCell(target);
|
|
43605
|
-
if (clipboardOption?.pasteOption
|
|
43606
|
-
const
|
|
43607
|
-
const
|
|
43608
|
-
|
|
43609
|
-
|
|
43610
|
-
bottom: targetBorders?.bottom || originBorders?.bottom,
|
|
43611
|
-
left: targetBorders?.left || originBorders?.left,
|
|
43612
|
-
right: targetBorders?.right || originBorders?.right,
|
|
43613
|
-
};
|
|
43614
|
-
this.dispatch("SET_BORDER", { sheetId, col, row, border });
|
|
43845
|
+
if (clipboardOption?.pasteOption === "onlyValue") {
|
|
43846
|
+
const locale = this.getters.getLocale();
|
|
43847
|
+
const content = formatValue(origin.evaluatedCell.value, { locale });
|
|
43848
|
+
this.dispatch("UPDATE_CELL", { ...target, content });
|
|
43849
|
+
return;
|
|
43615
43850
|
}
|
|
43616
|
-
|
|
43617
|
-
|
|
43618
|
-
|
|
43619
|
-
|
|
43620
|
-
|
|
43621
|
-
|
|
43622
|
-
|
|
43623
|
-
|
|
43624
|
-
|
|
43625
|
-
|
|
43626
|
-
|
|
43627
|
-
|
|
43628
|
-
|
|
43629
|
-
|
|
43630
|
-
}
|
|
43631
|
-
|
|
43632
|
-
|
|
43633
|
-
|
|
43634
|
-
|
|
43851
|
+
const targetBorders = this.getters.getCellBorder(target);
|
|
43852
|
+
const originBorders = origin.border;
|
|
43853
|
+
const border = {
|
|
43854
|
+
top: targetBorders?.top || originBorders?.top,
|
|
43855
|
+
bottom: targetBorders?.bottom || originBorders?.bottom,
|
|
43856
|
+
left: targetBorders?.left || originBorders?.left,
|
|
43857
|
+
right: targetBorders?.right || originBorders?.right,
|
|
43858
|
+
};
|
|
43859
|
+
this.dispatch("SET_BORDER", { sheetId, col, row, border });
|
|
43860
|
+
if (clipboardOption?.pasteOption === "onlyFormat") {
|
|
43861
|
+
this.dispatch("UPDATE_CELL", {
|
|
43862
|
+
...target,
|
|
43863
|
+
style: origin.cell?.style ?? null,
|
|
43864
|
+
format: origin.cell?.format ?? origin.evaluatedCell.format ?? targetCell.format,
|
|
43865
|
+
});
|
|
43866
|
+
return;
|
|
43867
|
+
}
|
|
43868
|
+
const content = origin.cell && origin.cell.isFormula && operation === "COPY"
|
|
43869
|
+
? this.getters.getTranslatedCellFormula(sheetId, col - origin.position.col, row - origin.position.row, origin.cell.compiledFormula)
|
|
43870
|
+
: origin.cell?.content;
|
|
43871
|
+
if (content !== "" || origin.cell?.format || origin.cell?.style) {
|
|
43635
43872
|
this.dispatch("UPDATE_CELL", {
|
|
43636
43873
|
...target,
|
|
43637
43874
|
content,
|
|
43638
|
-
style: origin.cell
|
|
43639
|
-
format: origin.cell
|
|
43875
|
+
style: origin.cell?.style || null,
|
|
43876
|
+
format: origin.cell?.format,
|
|
43640
43877
|
});
|
|
43641
43878
|
}
|
|
43642
43879
|
else if (targetCell) {
|
|
43643
|
-
|
|
43644
|
-
this.dispatch("UPDATE_CELL", { ...target, content: "" });
|
|
43645
|
-
}
|
|
43646
|
-
else if (clipboardOption?.pasteOption === "onlyFormat") {
|
|
43647
|
-
this.dispatch("UPDATE_CELL", { ...target, style: null, format: "" });
|
|
43648
|
-
}
|
|
43649
|
-
else {
|
|
43650
|
-
this.dispatch("CLEAR_CELL", target);
|
|
43651
|
-
}
|
|
43880
|
+
this.dispatch("CLEAR_CELL", target);
|
|
43652
43881
|
}
|
|
43653
43882
|
}
|
|
43654
43883
|
/**
|
|
@@ -43710,22 +43939,28 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
|
|
|
43710
43939
|
return (this.cells
|
|
43711
43940
|
.map((cells) => {
|
|
43712
43941
|
return cells
|
|
43713
|
-
.map((c) => this.getters.shouldShowFormulas() && c
|
|
43942
|
+
.map((c) => this.getters.shouldShowFormulas() && c?.cell?.isFormula
|
|
43714
43943
|
? c.cell?.content || ""
|
|
43715
|
-
: c
|
|
43944
|
+
: c?.evaluatedCell?.formattedValue || "")
|
|
43716
43945
|
.join("\t");
|
|
43717
43946
|
})
|
|
43718
43947
|
.join("\n") || "\t");
|
|
43719
43948
|
}
|
|
43720
43949
|
getHTMLContent() {
|
|
43721
43950
|
if (this.cells.length === 1 && this.cells[0].length === 1) {
|
|
43951
|
+
if (!this.cells[0][0]) {
|
|
43952
|
+
return "";
|
|
43953
|
+
}
|
|
43722
43954
|
return this.getters.getCellText(this.cells[0][0].position);
|
|
43723
43955
|
}
|
|
43724
43956
|
let htmlTable = '<table border="1" style="border-collapse:collapse">';
|
|
43725
43957
|
for (const row of this.cells) {
|
|
43726
43958
|
htmlTable += "<tr>";
|
|
43727
43959
|
for (const cell of row) {
|
|
43728
|
-
|
|
43960
|
+
if (!cell) {
|
|
43961
|
+
continue;
|
|
43962
|
+
}
|
|
43963
|
+
const cssStyle = cssPropertiesToCss(cellStyleToCss(this.getters.getCellComputedStyle(cell.position)));
|
|
43729
43964
|
const cellText = this.getters.getCellText(cell.position);
|
|
43730
43965
|
htmlTable += `<td style="${cssStyle}">` + xmlEscape(cellText) + "</td>";
|
|
43731
43966
|
}
|
|
@@ -44053,24 +44288,49 @@ var Direction;
|
|
|
44053
44288
|
*/
|
|
44054
44289
|
class FindAndReplacePlugin extends UIPlugin {
|
|
44055
44290
|
static layers = [3 /* LAYERS.Search */];
|
|
44056
|
-
static getters = [
|
|
44057
|
-
|
|
44291
|
+
static getters = [
|
|
44292
|
+
"getSearchMatches",
|
|
44293
|
+
"getCurrentSelectedMatchIndex",
|
|
44294
|
+
"getSearchOptions",
|
|
44295
|
+
"getAllSheetMatchesCount",
|
|
44296
|
+
"getActiveSheetMatchesCount",
|
|
44297
|
+
"getSpecificRangeMatchesCount",
|
|
44298
|
+
];
|
|
44299
|
+
allSheetsMatches = [];
|
|
44300
|
+
activeSheetMatches = [];
|
|
44301
|
+
specificRangeMatches = [];
|
|
44302
|
+
// fixme: why do we make selectedMatchIndex on top of a selected
|
|
44303
|
+
// property in the matches?
|
|
44058
44304
|
selectedMatchIndex = null;
|
|
44059
44305
|
currentSearchRegex = null;
|
|
44060
44306
|
searchOptions = {
|
|
44061
44307
|
matchCase: false,
|
|
44062
44308
|
exactMatch: false,
|
|
44063
44309
|
searchFormulas: false,
|
|
44310
|
+
searchScope: "allSheets",
|
|
44311
|
+
specificRange: undefined,
|
|
44064
44312
|
};
|
|
44065
44313
|
toSearch = "";
|
|
44066
44314
|
isSearchDirty = false;
|
|
44315
|
+
get searchMatches() {
|
|
44316
|
+
switch (this.searchOptions.searchScope) {
|
|
44317
|
+
case "allSheets":
|
|
44318
|
+
return this.allSheetsMatches;
|
|
44319
|
+
case "activeSheet":
|
|
44320
|
+
return this.activeSheetMatches;
|
|
44321
|
+
case "specificRange":
|
|
44322
|
+
return this.specificRangeMatches;
|
|
44323
|
+
}
|
|
44324
|
+
}
|
|
44067
44325
|
// ---------------------------------------------------------------------------
|
|
44068
44326
|
// Command Handling
|
|
44069
44327
|
// ---------------------------------------------------------------------------
|
|
44070
44328
|
handle(cmd) {
|
|
44071
44329
|
switch (cmd.type) {
|
|
44072
44330
|
case "UPDATE_SEARCH":
|
|
44073
|
-
|
|
44331
|
+
const rangeData = cmd.searchOptions.specificRange;
|
|
44332
|
+
const specificRange = rangeData && this.getters.getRangeFromRangeData(rangeData);
|
|
44333
|
+
this.updateSearch(cmd.toSearch, { ...cmd.searchOptions, specificRange });
|
|
44074
44334
|
break;
|
|
44075
44335
|
case "CLEAR_SEARCH":
|
|
44076
44336
|
this.clearSearch();
|
|
@@ -44100,7 +44360,9 @@ class FindAndReplacePlugin extends UIPlugin {
|
|
|
44100
44360
|
this.isSearchDirty = true;
|
|
44101
44361
|
break;
|
|
44102
44362
|
case "ACTIVATE_SHEET":
|
|
44103
|
-
this.
|
|
44363
|
+
if (this.searchOptions.searchScope === "activeSheet") {
|
|
44364
|
+
this.isSearchDirty = true;
|
|
44365
|
+
}
|
|
44104
44366
|
break;
|
|
44105
44367
|
}
|
|
44106
44368
|
}
|
|
@@ -44119,6 +44381,18 @@ class FindAndReplacePlugin extends UIPlugin {
|
|
|
44119
44381
|
getCurrentSelectedMatchIndex() {
|
|
44120
44382
|
return this.selectedMatchIndex;
|
|
44121
44383
|
}
|
|
44384
|
+
getSearchOptions() {
|
|
44385
|
+
return { ...this.searchOptions, specificRange: this.searchOptions.specificRange?.rangeData };
|
|
44386
|
+
}
|
|
44387
|
+
getAllSheetMatchesCount() {
|
|
44388
|
+
return this.allSheetsMatches.length;
|
|
44389
|
+
}
|
|
44390
|
+
getActiveSheetMatchesCount() {
|
|
44391
|
+
return this.activeSheetMatches.length;
|
|
44392
|
+
}
|
|
44393
|
+
getSpecificRangeMatchesCount() {
|
|
44394
|
+
return this.specificRangeMatches.length;
|
|
44395
|
+
}
|
|
44122
44396
|
// ---------------------------------------------------------------------------
|
|
44123
44397
|
// Search
|
|
44124
44398
|
// ---------------------------------------------------------------------------
|
|
@@ -44139,8 +44413,8 @@ class FindAndReplacePlugin extends UIPlugin {
|
|
|
44139
44413
|
* refresh the matches according to the current search options
|
|
44140
44414
|
*/
|
|
44141
44415
|
refreshSearch() {
|
|
44142
|
-
|
|
44143
|
-
this.
|
|
44416
|
+
this.selectedMatchIndex = null;
|
|
44417
|
+
this.findMatches();
|
|
44144
44418
|
this.selectNextCell(Direction.current);
|
|
44145
44419
|
}
|
|
44146
44420
|
/**
|
|
@@ -44155,45 +44429,65 @@ class FindAndReplacePlugin extends UIPlugin {
|
|
|
44155
44429
|
}
|
|
44156
44430
|
this.currentSearchRegex = RegExp(searchValue, flags);
|
|
44157
44431
|
}
|
|
44432
|
+
getSheetsInSearchOrder() {
|
|
44433
|
+
switch (this.searchOptions.searchScope) {
|
|
44434
|
+
case "allSheets":
|
|
44435
|
+
const sheetIds = this.getters.getSheetIds();
|
|
44436
|
+
const activeSheetIndex = sheetIds.findIndex((id) => id === this.getters.getActiveSheetId());
|
|
44437
|
+
return [
|
|
44438
|
+
sheetIds[activeSheetIndex],
|
|
44439
|
+
...sheetIds.slice(activeSheetIndex + 1),
|
|
44440
|
+
...sheetIds.slice(0, activeSheetIndex),
|
|
44441
|
+
];
|
|
44442
|
+
case "activeSheet":
|
|
44443
|
+
return [this.getters.getActiveSheetId()];
|
|
44444
|
+
case "specificRange":
|
|
44445
|
+
const specificRange = this.searchOptions.specificRange;
|
|
44446
|
+
if (!specificRange) {
|
|
44447
|
+
return [];
|
|
44448
|
+
}
|
|
44449
|
+
return specificRange ? [specificRange.sheetId] : [];
|
|
44450
|
+
}
|
|
44451
|
+
}
|
|
44158
44452
|
/**
|
|
44159
44453
|
* Find matches using the current regex
|
|
44160
44454
|
*/
|
|
44161
44455
|
findMatches() {
|
|
44162
|
-
const sheetId = this.getters.getActiveSheetId();
|
|
44163
|
-
const cells = this.getters.getCells(sheetId);
|
|
44164
44456
|
const matches = [];
|
|
44165
|
-
if (this.toSearch
|
|
44166
|
-
for (const
|
|
44167
|
-
|
|
44168
|
-
|
|
44457
|
+
if (this.toSearch) {
|
|
44458
|
+
for (const sheetId of this.getters.getSheetIds()) {
|
|
44459
|
+
matches.push(...this.findMatchesInSheet(sheetId));
|
|
44460
|
+
}
|
|
44461
|
+
}
|
|
44462
|
+
// set results
|
|
44463
|
+
this.allSheetsMatches = matches;
|
|
44464
|
+
this.activeSheetMatches = matches.filter((match) => match.sheetId === this.getters.getActiveSheetId());
|
|
44465
|
+
if (this.searchOptions.specificRange) {
|
|
44466
|
+
const { sheetId, zone } = this.searchOptions.specificRange;
|
|
44467
|
+
this.specificRangeMatches = matches.filter((match) => match.sheetId === sheetId && isInside(match.col, match.row, zone));
|
|
44468
|
+
}
|
|
44469
|
+
else {
|
|
44470
|
+
this.specificRangeMatches = [];
|
|
44471
|
+
}
|
|
44472
|
+
}
|
|
44473
|
+
findMatchesInSheet(sheetId) {
|
|
44474
|
+
const matches = [];
|
|
44475
|
+
const { left, right, top, bottom } = this.getters.getSheetZone(sheetId);
|
|
44476
|
+
for (let row = top; row <= bottom; row++) {
|
|
44477
|
+
for (let col = left; col <= right; col++) {
|
|
44169
44478
|
const isColHidden = this.getters.isColHidden(sheetId, col);
|
|
44170
44479
|
const isRowHidden = this.getters.isRowHidden(sheetId, row);
|
|
44171
44480
|
if (isColHidden || isRowHidden) {
|
|
44172
44481
|
continue;
|
|
44173
44482
|
}
|
|
44174
|
-
|
|
44175
|
-
|
|
44483
|
+
const cellPosition = { sheetId, col, row };
|
|
44484
|
+
if (this.currentSearchRegex?.test(this.getSearchableString(cellPosition))) {
|
|
44485
|
+
const match = { sheetId, col, row };
|
|
44176
44486
|
matches.push(match);
|
|
44177
44487
|
}
|
|
44178
|
-
for (const spreadPosition of this.getters.getSpreadPositionsOf(cellPosition)) {
|
|
44179
|
-
if (this.currentSearchRegex.test(this.getSearchableString(spreadPosition))) {
|
|
44180
|
-
const match = {
|
|
44181
|
-
col: spreadPosition.col,
|
|
44182
|
-
row: spreadPosition.row,
|
|
44183
|
-
selected: false,
|
|
44184
|
-
};
|
|
44185
|
-
matches.push(match);
|
|
44186
|
-
}
|
|
44187
|
-
}
|
|
44188
44488
|
}
|
|
44189
44489
|
}
|
|
44190
|
-
return matches
|
|
44191
|
-
}
|
|
44192
|
-
sortByRowThenColumn(a, b) {
|
|
44193
|
-
if (a.row === b.row) {
|
|
44194
|
-
return a.col - b.col;
|
|
44195
|
-
}
|
|
44196
|
-
return a.row > b.row ? 1 : -1;
|
|
44490
|
+
return matches;
|
|
44197
44491
|
}
|
|
44198
44492
|
/**
|
|
44199
44493
|
* Changes the selected search cell. Given a direction it will
|
|
@@ -44211,30 +44505,47 @@ class FindAndReplacePlugin extends UIPlugin {
|
|
|
44211
44505
|
}
|
|
44212
44506
|
let nextIndex;
|
|
44213
44507
|
if (this.selectedMatchIndex === null) {
|
|
44214
|
-
|
|
44508
|
+
let nextMatchIndex = -1;
|
|
44509
|
+
// if search is not available in current sheet will select in next sheet
|
|
44510
|
+
for (const sheetId of this.getSheetsInSearchOrder()) {
|
|
44511
|
+
nextMatchIndex = matches.findIndex((match) => match.sheetId === sheetId);
|
|
44512
|
+
if (nextMatchIndex !== -1) {
|
|
44513
|
+
break;
|
|
44514
|
+
}
|
|
44515
|
+
}
|
|
44516
|
+
nextIndex = nextMatchIndex;
|
|
44215
44517
|
}
|
|
44216
44518
|
else {
|
|
44217
44519
|
nextIndex = this.selectedMatchIndex + indexChange;
|
|
44218
44520
|
}
|
|
44219
|
-
//
|
|
44220
|
-
nextIndex = (
|
|
44521
|
+
// loop index value inside the array (index -1 => last index)
|
|
44522
|
+
nextIndex = (nextIndex + matches.length) % matches.length;
|
|
44221
44523
|
this.selectedMatchIndex = nextIndex;
|
|
44524
|
+
const selectedMatch = matches[nextIndex];
|
|
44525
|
+
// Switch to the sheet where the match is located
|
|
44526
|
+
if (this.getters.getActiveSheetId() !== selectedMatch.sheetId) {
|
|
44527
|
+
this.dispatch("ACTIVATE_SHEET", {
|
|
44528
|
+
sheetIdFrom: this.getters.getActiveSheetId(),
|
|
44529
|
+
sheetIdTo: selectedMatch.sheetId,
|
|
44530
|
+
});
|
|
44531
|
+
}
|
|
44222
44532
|
// we want grid selection to capture the selection stream
|
|
44223
44533
|
this.selection.getBackToDefault();
|
|
44224
|
-
this.selection.selectCell(
|
|
44225
|
-
for (let index = 0; index < this.searchMatches.length; index++) {
|
|
44226
|
-
this.searchMatches[index].selected = index === this.selectedMatchIndex;
|
|
44227
|
-
}
|
|
44534
|
+
this.selection.selectCell(selectedMatch.col, selectedMatch.row);
|
|
44228
44535
|
}
|
|
44229
44536
|
clearSearch() {
|
|
44230
44537
|
this.toSearch = "";
|
|
44231
|
-
this.searchMatches = [];
|
|
44232
44538
|
this.selectedMatchIndex = null;
|
|
44233
44539
|
this.currentSearchRegex = null;
|
|
44540
|
+
this.allSheetsMatches = [];
|
|
44541
|
+
this.activeSheetMatches = [];
|
|
44542
|
+
this.specificRangeMatches = [];
|
|
44234
44543
|
this.searchOptions = {
|
|
44235
44544
|
matchCase: false,
|
|
44236
44545
|
exactMatch: false,
|
|
44237
44546
|
searchFormulas: false,
|
|
44547
|
+
searchScope: "allSheets",
|
|
44548
|
+
specificRange: undefined,
|
|
44238
44549
|
};
|
|
44239
44550
|
}
|
|
44240
44551
|
// ---------------------------------------------------------------------------
|
|
@@ -44244,9 +44555,7 @@ class FindAndReplacePlugin extends UIPlugin {
|
|
|
44244
44555
|
if (!this.currentSearchRegex) {
|
|
44245
44556
|
return;
|
|
44246
44557
|
}
|
|
44247
|
-
const
|
|
44248
|
-
const position = { sheetId, ...selectedMatch };
|
|
44249
|
-
const cell = this.getters.getCell(position);
|
|
44558
|
+
const cell = this.getters.getCell(selectedMatch);
|
|
44250
44559
|
if (!cell?.content) {
|
|
44251
44560
|
return;
|
|
44252
44561
|
}
|
|
@@ -44254,10 +44563,10 @@ class FindAndReplacePlugin extends UIPlugin {
|
|
|
44254
44563
|
return;
|
|
44255
44564
|
}
|
|
44256
44565
|
const replaceRegex = new RegExp(this.currentSearchRegex.source, this.currentSearchRegex.flags + "g");
|
|
44257
|
-
const toReplace = this.getSearchableString(
|
|
44566
|
+
const toReplace = this.getSearchableString(selectedMatch);
|
|
44258
44567
|
const content = toReplace.replace(replaceRegex, replaceWith);
|
|
44259
44568
|
const canonicalContent = canonicalizeNumberContent(content, this.getters.getLocale());
|
|
44260
|
-
this.dispatch("UPDATE_CELL", { ...
|
|
44569
|
+
this.dispatch("UPDATE_CELL", { ...selectedMatch, content: canonicalContent });
|
|
44261
44570
|
}
|
|
44262
44571
|
/**
|
|
44263
44572
|
* Replace the value of the currently selected match
|
|
@@ -44288,7 +44597,10 @@ class FindAndReplacePlugin extends UIPlugin {
|
|
|
44288
44597
|
drawGrid(renderingContext) {
|
|
44289
44598
|
const { ctx } = renderingContext;
|
|
44290
44599
|
const sheetId = this.getters.getActiveSheetId();
|
|
44291
|
-
for (const match of this.searchMatches) {
|
|
44600
|
+
for (const [index, match] of this.searchMatches.entries()) {
|
|
44601
|
+
if (match.sheetId !== sheetId) {
|
|
44602
|
+
continue; // Skip drawing matches from other sheets
|
|
44603
|
+
}
|
|
44292
44604
|
const merge = this.getters.getMerge({ sheetId, col: match.col, row: match.row });
|
|
44293
44605
|
const left = merge ? merge.left : match.col;
|
|
44294
44606
|
const right = merge ? merge.right : match.col;
|
|
@@ -44298,12 +44610,21 @@ class FindAndReplacePlugin extends UIPlugin {
|
|
|
44298
44610
|
if (width > 0 && height > 0) {
|
|
44299
44611
|
ctx.fillStyle = BACKGROUND_COLOR;
|
|
44300
44612
|
ctx.fillRect(x, y, width, height);
|
|
44301
|
-
if (
|
|
44613
|
+
if (index === this.selectedMatchIndex) {
|
|
44302
44614
|
ctx.strokeStyle = BORDER_COLOR;
|
|
44303
44615
|
ctx.strokeRect(x, y, width, height);
|
|
44304
44616
|
}
|
|
44305
44617
|
}
|
|
44306
44618
|
}
|
|
44619
|
+
if (this.searchOptions.searchScope === "specificRange") {
|
|
44620
|
+
const range = this.searchOptions.specificRange;
|
|
44621
|
+
if (!range || range.sheetId !== sheetId) {
|
|
44622
|
+
return;
|
|
44623
|
+
}
|
|
44624
|
+
const { x, y, width, height } = this.getters.getVisibleRect(range.zone);
|
|
44625
|
+
ctx.strokeStyle = BORDER_COLOR;
|
|
44626
|
+
ctx.strokeRect(x, y, width, height);
|
|
44627
|
+
}
|
|
44307
44628
|
}
|
|
44308
44629
|
}
|
|
44309
44630
|
|
|
@@ -45562,6 +45883,9 @@ class SelectionInputsManagerPlugin extends UIPlugin {
|
|
|
45562
45883
|
// Other
|
|
45563
45884
|
// ---------------------------------------------------------------------------
|
|
45564
45885
|
initInput(id, initialRanges, inputHasSingleRange = false) {
|
|
45886
|
+
if (this.inputs[id]) {
|
|
45887
|
+
this.unfocus();
|
|
45888
|
+
}
|
|
45565
45889
|
this.inputs[id] = new SelectionInputPlugin(this.config, initialRanges, inputHasSingleRange);
|
|
45566
45890
|
if (initialRanges.length === 0) {
|
|
45567
45891
|
const input = this.inputs[id];
|
|
@@ -46270,7 +46594,7 @@ class HistoryPlugin extends UIPlugin {
|
|
|
46270
46594
|
* Ignore standard undo/redo revisions (that are empty)
|
|
46271
46595
|
*/
|
|
46272
46596
|
getPossibleRevisionToRepeat() {
|
|
46273
|
-
return this.session.getLastLocalNonEmptyRevision(
|
|
46597
|
+
return this.session.getLastLocalNonEmptyRevision();
|
|
46274
46598
|
}
|
|
46275
46599
|
}
|
|
46276
46600
|
|
|
@@ -46769,11 +47093,14 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
46769
47093
|
}
|
|
46770
47094
|
const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
|
|
46771
47095
|
this.state.paste(cmd.target, { pasteOption, shouldPasteCF: true, selectTarget: true });
|
|
47096
|
+
if (this.state.operation === "CUT") {
|
|
47097
|
+
this.state = undefined;
|
|
47098
|
+
}
|
|
46772
47099
|
this.lastPasteState = this.state;
|
|
46773
47100
|
if (this.paintFormatStatus === "oneOff") {
|
|
46774
47101
|
this.paintFormatStatus = "inactive";
|
|
46775
|
-
this.status = "invisible";
|
|
46776
47102
|
}
|
|
47103
|
+
this.status = "invisible";
|
|
46777
47104
|
break;
|
|
46778
47105
|
case "COPY_PASTE_CELLS_ABOVE":
|
|
46779
47106
|
{
|
|
@@ -47000,92 +47327,6 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
47000
47327
|
}
|
|
47001
47328
|
}
|
|
47002
47329
|
|
|
47003
|
-
/**
|
|
47004
|
-
* Change the reference types inside the given token, if the token represent a range or a cell
|
|
47005
|
-
*
|
|
47006
|
-
* Eg. :
|
|
47007
|
-
* A1 => $A$1 => A$1 => $A1 => A1
|
|
47008
|
-
* A1:$B$1 => $A$1:B$1 => A$1:$B1 => $A1:B1 => A1:$B$1
|
|
47009
|
-
*/
|
|
47010
|
-
function loopThroughReferenceType(token) {
|
|
47011
|
-
if (token.type !== "REFERENCE")
|
|
47012
|
-
return token;
|
|
47013
|
-
const { xc, sheetName } = splitReference(token.value);
|
|
47014
|
-
const [left, right] = xc.split(":");
|
|
47015
|
-
const sheetRef = sheetName ? `${getCanonicalSheetName(sheetName)}!` : "";
|
|
47016
|
-
const updatedLeft = getTokenNextReferenceType(left);
|
|
47017
|
-
const updatedRight = right ? `:${getTokenNextReferenceType(right)}` : "";
|
|
47018
|
-
return { ...token, value: sheetRef + updatedLeft + updatedRight };
|
|
47019
|
-
}
|
|
47020
|
-
/**
|
|
47021
|
-
* Get a new token with a changed type of reference from the given cell token symbol.
|
|
47022
|
-
* Undefined behavior if given a token other than a cell or if the Xc contains a sheet reference
|
|
47023
|
-
*
|
|
47024
|
-
* A1 => $A$1 => A$1 => $A1 => A1
|
|
47025
|
-
*/
|
|
47026
|
-
function getTokenNextReferenceType(xc) {
|
|
47027
|
-
switch (getReferenceType(xc)) {
|
|
47028
|
-
case "none":
|
|
47029
|
-
xc = setXcToReferenceType(xc, "colrow");
|
|
47030
|
-
break;
|
|
47031
|
-
case "colrow":
|
|
47032
|
-
xc = setXcToReferenceType(xc, "row");
|
|
47033
|
-
break;
|
|
47034
|
-
case "row":
|
|
47035
|
-
xc = setXcToReferenceType(xc, "col");
|
|
47036
|
-
break;
|
|
47037
|
-
case "col":
|
|
47038
|
-
xc = setXcToReferenceType(xc, "none");
|
|
47039
|
-
break;
|
|
47040
|
-
}
|
|
47041
|
-
return xc;
|
|
47042
|
-
}
|
|
47043
|
-
/**
|
|
47044
|
-
* Returns the given XC with the given reference type.
|
|
47045
|
-
*/
|
|
47046
|
-
function setXcToReferenceType(xc, referenceType) {
|
|
47047
|
-
xc = xc.replace(/\$/g, "");
|
|
47048
|
-
let indexOfNumber;
|
|
47049
|
-
switch (referenceType) {
|
|
47050
|
-
case "col":
|
|
47051
|
-
return "$" + xc;
|
|
47052
|
-
case "row":
|
|
47053
|
-
indexOfNumber = xc.search(/[0-9]/);
|
|
47054
|
-
return xc.slice(0, indexOfNumber) + "$" + xc.slice(indexOfNumber);
|
|
47055
|
-
case "colrow":
|
|
47056
|
-
indexOfNumber = xc.search(/[0-9]/);
|
|
47057
|
-
xc = xc.slice(0, indexOfNumber) + "$" + xc.slice(indexOfNumber);
|
|
47058
|
-
return "$" + xc;
|
|
47059
|
-
case "none":
|
|
47060
|
-
return xc;
|
|
47061
|
-
}
|
|
47062
|
-
}
|
|
47063
|
-
/**
|
|
47064
|
-
* Return the type of reference used in the given XC of a cell.
|
|
47065
|
-
* Undefined behavior if the XC have a sheet reference
|
|
47066
|
-
*/
|
|
47067
|
-
function getReferenceType(xcCell) {
|
|
47068
|
-
if (isColAndRowFixed(xcCell)) {
|
|
47069
|
-
return "colrow";
|
|
47070
|
-
}
|
|
47071
|
-
else if (isColFixed(xcCell)) {
|
|
47072
|
-
return "col";
|
|
47073
|
-
}
|
|
47074
|
-
else if (isRowFixed(xcCell)) {
|
|
47075
|
-
return "row";
|
|
47076
|
-
}
|
|
47077
|
-
return "none";
|
|
47078
|
-
}
|
|
47079
|
-
function isColFixed(xc) {
|
|
47080
|
-
return xc.startsWith("$");
|
|
47081
|
-
}
|
|
47082
|
-
function isRowFixed(xc) {
|
|
47083
|
-
return xc.includes("$", 1);
|
|
47084
|
-
}
|
|
47085
|
-
function isColAndRowFixed(xc) {
|
|
47086
|
-
return xc.startsWith("$") && xc.length > 1 && xc.slice(1).includes("$");
|
|
47087
|
-
}
|
|
47088
|
-
|
|
47089
47330
|
const CELL_DELETED_MESSAGE = _t("The cell you are trying to edit has been deleted.");
|
|
47090
47331
|
class EditionPlugin extends UIPlugin {
|
|
47091
47332
|
static getters = [
|
|
@@ -47824,6 +48065,12 @@ class FilterEvaluationPlugin extends UIPlugin {
|
|
|
47824
48065
|
break;
|
|
47825
48066
|
case "HIDE_COLUMNS_ROWS":
|
|
47826
48067
|
case "UNHIDE_COLUMNS_ROWS":
|
|
48068
|
+
case "GROUP_HEADERS":
|
|
48069
|
+
case "UNGROUP_HEADERS":
|
|
48070
|
+
case "FOLD_HEADER_GROUP":
|
|
48071
|
+
case "UNFOLD_HEADER_GROUP":
|
|
48072
|
+
case "FOLD_ALL_HEADER_GROUPS":
|
|
48073
|
+
case "UNFOLD_ALL_HEADER_GROUPS":
|
|
47827
48074
|
this.updateHiddenRows();
|
|
47828
48075
|
break;
|
|
47829
48076
|
case "UPDATE_FILTER":
|
|
@@ -48003,32 +48250,32 @@ const selectionStatisticFunctions = [
|
|
|
48003
48250
|
{
|
|
48004
48251
|
name: _t("Sum"),
|
|
48005
48252
|
types: [CellValueType.number],
|
|
48006
|
-
compute: (values, locale) =>
|
|
48253
|
+
compute: (values, locale) => sum([[values]], locale),
|
|
48007
48254
|
},
|
|
48008
48255
|
{
|
|
48009
48256
|
name: _t("Avg"),
|
|
48010
48257
|
types: [CellValueType.number],
|
|
48011
|
-
compute: (values, locale) =>
|
|
48258
|
+
compute: (values, locale) => average([[values]], locale),
|
|
48012
48259
|
},
|
|
48013
48260
|
{
|
|
48014
48261
|
name: _t("Min"),
|
|
48015
48262
|
types: [CellValueType.number],
|
|
48016
|
-
compute: (values, locale) =>
|
|
48263
|
+
compute: (values, locale) => min([[values]], locale),
|
|
48017
48264
|
},
|
|
48018
48265
|
{
|
|
48019
48266
|
name: _t("Max"),
|
|
48020
48267
|
types: [CellValueType.number],
|
|
48021
|
-
compute: (values, locale) =>
|
|
48268
|
+
compute: (values, locale) => max([[values]], locale),
|
|
48022
48269
|
},
|
|
48023
48270
|
{
|
|
48024
48271
|
name: _t("Count"),
|
|
48025
48272
|
types: [CellValueType.number, CellValueType.text, CellValueType.boolean, CellValueType.error],
|
|
48026
|
-
compute: (values
|
|
48273
|
+
compute: (values) => countAny([[values]]),
|
|
48027
48274
|
},
|
|
48028
48275
|
{
|
|
48029
48276
|
name: _t("Count Numbers"),
|
|
48030
48277
|
types: [CellValueType.number, CellValueType.text, CellValueType.boolean, CellValueType.error],
|
|
48031
|
-
compute: (values, locale) =>
|
|
48278
|
+
compute: (values, locale) => countNumbers([[values]], locale),
|
|
48032
48279
|
},
|
|
48033
48280
|
];
|
|
48034
48281
|
/**
|
|
@@ -48525,7 +48772,7 @@ class GridSelectionPlugin extends UIPlugin {
|
|
|
48525
48772
|
sheetId: cmd.sheetId,
|
|
48526
48773
|
base: cmd.base,
|
|
48527
48774
|
quantity: thickness,
|
|
48528
|
-
position:
|
|
48775
|
+
position: cmd.position,
|
|
48529
48776
|
});
|
|
48530
48777
|
const isCol = cmd.dimension === "COL";
|
|
48531
48778
|
const start = cmd.elements[0];
|
|
@@ -48542,12 +48789,13 @@ class GridSelectionPlugin extends UIPlugin {
|
|
|
48542
48789
|
},
|
|
48543
48790
|
];
|
|
48544
48791
|
const state = new ClipboardCellsState(target, "CUT", this.getters, this.dispatch, this.selection);
|
|
48792
|
+
const base = isBasedBefore ? cmd.base : cmd.base + 1;
|
|
48545
48793
|
const pasteTarget = [
|
|
48546
48794
|
{
|
|
48547
|
-
left: isCol ?
|
|
48548
|
-
right: isCol ?
|
|
48549
|
-
top: !isCol ?
|
|
48550
|
-
bottom: !isCol ?
|
|
48795
|
+
left: isCol ? base : 0,
|
|
48796
|
+
right: isCol ? base + thickness - 1 : this.getters.getNumberCols(cmd.sheetId) - 1,
|
|
48797
|
+
top: !isCol ? base : 0,
|
|
48798
|
+
bottom: !isCol ? base + thickness - 1 : this.getters.getNumberRows(cmd.sheetId) - 1,
|
|
48551
48799
|
},
|
|
48552
48800
|
];
|
|
48553
48801
|
state.paste(pasteTarget, { selectTarget: true });
|
|
@@ -48582,6 +48830,11 @@ class GridSelectionPlugin extends UIPlugin {
|
|
|
48582
48830
|
doesElementsHaveCommonMerges(id, cmd.base - 1, cmd.base)) {
|
|
48583
48831
|
return "WillRemoveExistingMerge" /* CommandResult.WillRemoveExistingMerge */;
|
|
48584
48832
|
}
|
|
48833
|
+
const headers = [cmd.base, ...cmd.elements];
|
|
48834
|
+
const maxHeaderValue = isCol ? this.getters.getNumberCols(id) : this.getters.getNumberRows(id);
|
|
48835
|
+
if (headers.some((h) => h < 0 || h >= maxHeaderValue)) {
|
|
48836
|
+
return "InvalidHeaderIndex" /* CommandResult.InvalidHeaderIndex */;
|
|
48837
|
+
}
|
|
48585
48838
|
return "Success" /* CommandResult.Success */;
|
|
48586
48839
|
}
|
|
48587
48840
|
//-------------------------------------------
|
|
@@ -48759,9 +49012,6 @@ class InternalViewport {
|
|
|
48759
49012
|
*/
|
|
48760
49013
|
adjustPosition(position) {
|
|
48761
49014
|
const sheetId = this.sheetId;
|
|
48762
|
-
if (!position) {
|
|
48763
|
-
position = this.getters.getSheetPosition(sheetId);
|
|
48764
|
-
}
|
|
48765
49015
|
const mainCellPosition = this.getters.getMainCellPosition({ sheetId, ...position });
|
|
48766
49016
|
const { col, row } = this.getters.getNextVisibleCellPosition(mainCellPosition);
|
|
48767
49017
|
if (isInside(col, this.boundaries.top, this.boundaries)) {
|
|
@@ -48774,56 +49024,50 @@ class InternalViewport {
|
|
|
48774
49024
|
adjustPositionX(targetCol) {
|
|
48775
49025
|
const sheetId = this.sheetId;
|
|
48776
49026
|
const { end } = this.getters.getColDimensions(sheetId, targetCol);
|
|
48777
|
-
const maxCol = this.getters.getNumberCols(sheetId);
|
|
48778
49027
|
if (this.offsetX + this.offsetCorrectionX + this.viewportWidth < end) {
|
|
49028
|
+
const maxCol = this.getters.getNumberCols(sheetId);
|
|
48779
49029
|
let finalTarget = targetCol;
|
|
48780
|
-
while (this.getters.isColHidden(sheetId, finalTarget) &&
|
|
49030
|
+
while (this.getters.isColHidden(sheetId, finalTarget) && finalTarget < maxCol) {
|
|
48781
49031
|
finalTarget++;
|
|
48782
49032
|
}
|
|
48783
49033
|
const finalTargetEnd = this.getters.getColDimensions(sheetId, finalTarget).end;
|
|
48784
49034
|
const startIndex = this.searchHeaderIndex("COL", finalTargetEnd - this.viewportWidth - this.offsetCorrectionX, this.boundaries.left);
|
|
48785
|
-
this.
|
|
49035
|
+
this.offsetScrollbarX =
|
|
48786
49036
|
this.getters.getColDimensions(sheetId, startIndex).end - this.offsetCorrectionX;
|
|
48787
|
-
this.offsetScrollbarX = this.offsetX;
|
|
48788
|
-
this.adjustViewportZoneX();
|
|
48789
49037
|
}
|
|
48790
49038
|
else if (this.left > targetCol) {
|
|
48791
49039
|
let finalTarget = targetCol;
|
|
48792
|
-
while (this.getters.isColHidden(sheetId, finalTarget) &&
|
|
49040
|
+
while (this.getters.isColHidden(sheetId, finalTarget) && finalTarget > 0) {
|
|
48793
49041
|
finalTarget--;
|
|
48794
49042
|
}
|
|
48795
|
-
this.
|
|
49043
|
+
this.offsetScrollbarX =
|
|
48796
49044
|
this.getters.getColDimensions(sheetId, finalTarget).start - this.offsetCorrectionX;
|
|
48797
|
-
this.offsetScrollbarX = this.offsetX;
|
|
48798
|
-
this.adjustViewportZoneX();
|
|
48799
49045
|
}
|
|
49046
|
+
this.adjustViewportZoneX();
|
|
48800
49047
|
}
|
|
48801
49048
|
adjustPositionY(targetRow) {
|
|
48802
49049
|
const sheetId = this.sheetId;
|
|
48803
49050
|
const { end } = this.getters.getRowDimensions(sheetId, targetRow);
|
|
48804
|
-
const maxRow = this.getters.getNumberRows(sheetId);
|
|
48805
49051
|
if (this.offsetY + this.viewportHeight + this.offsetCorrectionY < end) {
|
|
49052
|
+
const maxRow = this.getters.getNumberRows(sheetId);
|
|
48806
49053
|
let finalTarget = targetRow;
|
|
48807
|
-
while (this.getters.isRowHidden(sheetId, finalTarget) &&
|
|
49054
|
+
while (this.getters.isRowHidden(sheetId, finalTarget) && finalTarget < maxRow) {
|
|
48808
49055
|
finalTarget++;
|
|
48809
49056
|
}
|
|
48810
49057
|
const finalTargetEnd = this.getters.getRowDimensions(sheetId, finalTarget).end;
|
|
48811
49058
|
const startIndex = this.searchHeaderIndex("ROW", finalTargetEnd - this.viewportHeight - this.offsetCorrectionY, this.boundaries.top);
|
|
48812
|
-
this.
|
|
49059
|
+
this.offsetScrollbarY =
|
|
48813
49060
|
this.getters.getRowDimensions(sheetId, startIndex).end - this.offsetCorrectionY;
|
|
48814
|
-
this.offsetScrollbarY = this.offsetY;
|
|
48815
|
-
this.adjustViewportZoneY();
|
|
48816
49061
|
}
|
|
48817
49062
|
else if (this.top > targetRow) {
|
|
48818
49063
|
let finalTarget = targetRow;
|
|
48819
|
-
while (this.getters.isRowHidden(sheetId, finalTarget) &&
|
|
49064
|
+
while (this.getters.isRowHidden(sheetId, finalTarget) && finalTarget > 0) {
|
|
48820
49065
|
finalTarget--;
|
|
48821
49066
|
}
|
|
48822
|
-
this.
|
|
49067
|
+
this.offsetScrollbarY =
|
|
48823
49068
|
this.getters.getRowDimensions(sheetId, finalTarget).start - this.offsetCorrectionY;
|
|
48824
|
-
this.offsetScrollbarY = this.offsetY;
|
|
48825
|
-
this.adjustViewportZoneY();
|
|
48826
49069
|
}
|
|
49070
|
+
this.adjustViewportZoneY();
|
|
48827
49071
|
}
|
|
48828
49072
|
setViewportOffset(offsetX, offsetY) {
|
|
48829
49073
|
this.setViewportOffsetX(offsetX);
|
|
@@ -48839,11 +49083,10 @@ class InternalViewport {
|
|
|
48839
49083
|
* @returns Computes the absolute coordinate of a given zone inside the viewport
|
|
48840
49084
|
*/
|
|
48841
49085
|
getRect(zone) {
|
|
48842
|
-
const targetZone = intersection(zone, this
|
|
49086
|
+
const targetZone = intersection(zone, this);
|
|
48843
49087
|
if (targetZone) {
|
|
48844
|
-
const x = this.getters.getColRowOffset("COL", this.
|
|
48845
|
-
|
|
48846
|
-
const y = this.getters.getColRowOffset("ROW", this.zone.top, targetZone.top) + this.offsetCorrectionY;
|
|
49088
|
+
const x = this.getters.getColRowOffset("COL", this.left, targetZone.left) + this.offsetCorrectionX;
|
|
49089
|
+
const y = this.getters.getColRowOffset("ROW", this.top, targetZone.top) + this.offsetCorrectionY;
|
|
48847
49090
|
const width = Math.min(this.getters.getColRowOffset("COL", targetZone.left, targetZone.right + 1), this.viewportWidth);
|
|
48848
49091
|
const height = Math.min(this.getters.getColRowOffset("ROW", targetZone.top, targetZone.bottom + 1), this.viewportHeight);
|
|
48849
49092
|
return {
|
|
@@ -48853,9 +49096,7 @@ class InternalViewport {
|
|
|
48853
49096
|
height,
|
|
48854
49097
|
};
|
|
48855
49098
|
}
|
|
48856
|
-
|
|
48857
|
-
return undefined;
|
|
48858
|
-
}
|
|
49099
|
+
return undefined;
|
|
48859
49100
|
}
|
|
48860
49101
|
isVisible(col, row) {
|
|
48861
49102
|
const isInside = row <= this.bottom && row >= this.top && col >= this.left && col <= this.right;
|
|
@@ -48863,7 +49104,6 @@ class InternalViewport {
|
|
|
48863
49104
|
!this.getters.isColHidden(this.sheetId, col) &&
|
|
48864
49105
|
!this.getters.isRowHidden(this.sheetId, row));
|
|
48865
49106
|
}
|
|
48866
|
-
// PRIVATE
|
|
48867
49107
|
searchHeaderIndex(dimension, position, startIndex = 0) {
|
|
48868
49108
|
const sheetId = this.sheetId;
|
|
48869
49109
|
const headers = this.getters.getNumberHeaders(sheetId, dimension);
|
|
@@ -48886,9 +49126,6 @@ class InternalViewport {
|
|
|
48886
49126
|
}
|
|
48887
49127
|
return -1;
|
|
48888
49128
|
}
|
|
48889
|
-
get zone() {
|
|
48890
|
-
return { left: this.left, right: this.right, top: this.top, bottom: this.bottom };
|
|
48891
|
-
}
|
|
48892
49129
|
setViewportOffsetX(offsetX) {
|
|
48893
49130
|
if (!this.canScrollHorizontally) {
|
|
48894
49131
|
return;
|
|
@@ -48913,11 +49150,6 @@ class InternalViewport {
|
|
|
48913
49150
|
this.offsetScrollbarX = Math.max(0, viewportWidth - this.viewportWidth);
|
|
48914
49151
|
}
|
|
48915
49152
|
}
|
|
48916
|
-
this.left = this.getColIndex(this.offsetScrollbarX);
|
|
48917
|
-
this.right = this.getColIndex(this.offsetScrollbarX + this.viewportWidth);
|
|
48918
|
-
if (this.right === -1) {
|
|
48919
|
-
this.right = this.boundaries.right;
|
|
48920
|
-
}
|
|
48921
49153
|
this.adjustViewportZoneX();
|
|
48922
49154
|
}
|
|
48923
49155
|
/** Corrects the viewport's vertical offset based on the current structure
|
|
@@ -48930,11 +49162,6 @@ class InternalViewport {
|
|
|
48930
49162
|
this.offsetScrollbarY = Math.max(0, paneHeight - this.viewportHeight);
|
|
48931
49163
|
}
|
|
48932
49164
|
}
|
|
48933
|
-
this.top = this.getRowIndex(this.offsetScrollbarY);
|
|
48934
|
-
this.bottom = this.getRowIndex(this.offsetScrollbarY + this.viewportHeight);
|
|
48935
|
-
if (this.bottom === -1) {
|
|
48936
|
-
this.bottom = this.boundaries.bottom;
|
|
48937
|
-
}
|
|
48938
49165
|
this.adjustViewportZoneY();
|
|
48939
49166
|
}
|
|
48940
49167
|
/** Updates the pane zone and snapped offset based on its horizontal
|
|
@@ -49312,7 +49539,7 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
49312
49539
|
isVisibleInViewport({ sheetId, col, row }) {
|
|
49313
49540
|
return this.getSubViewports(sheetId).some((pane) => pane.isVisible(col, row));
|
|
49314
49541
|
}
|
|
49315
|
-
// =>
|
|
49542
|
+
// => returns the new offset
|
|
49316
49543
|
getEdgeScrollCol(x, previousX, startingX) {
|
|
49317
49544
|
let canEdgeScroll = false;
|
|
49318
49545
|
let direction = 0;
|
|
@@ -49627,10 +49854,13 @@ class HeaderPositionsUIPlugin extends UIPlugin {
|
|
|
49627
49854
|
}
|
|
49628
49855
|
break;
|
|
49629
49856
|
case "UPDATE_CELL":
|
|
49630
|
-
if ("content" in cmd || "format" in cmd
|
|
49857
|
+
if ("content" in cmd || "format" in cmd) {
|
|
49631
49858
|
this.headerPositions = {};
|
|
49632
49859
|
this.isDirty = true;
|
|
49633
49860
|
}
|
|
49861
|
+
else {
|
|
49862
|
+
this.headerPositions[cmd.sheetId] = this.computeHeaderPositionsOfSheet(cmd.sheetId);
|
|
49863
|
+
}
|
|
49634
49864
|
break;
|
|
49635
49865
|
case "UPDATE_FILTER":
|
|
49636
49866
|
case "REMOVE_FILTER_TABLE":
|
|
@@ -51787,6 +52017,8 @@ css /* scss */ `
|
|
|
51787
52017
|
*:before,
|
|
51788
52018
|
*:after {
|
|
51789
52019
|
box-sizing: content-box;
|
|
52020
|
+
/** rtl not supported ATM */
|
|
52021
|
+
direction: ltr;
|
|
51790
52022
|
}
|
|
51791
52023
|
.o-separator {
|
|
51792
52024
|
border-bottom: ${MENU_SEPARATOR_BORDER_WIDTH}px solid ${SEPARATOR_COLOR};
|
|
@@ -51943,6 +52175,7 @@ class Spreadsheet extends owl.Component {
|
|
|
51943
52175
|
};
|
|
51944
52176
|
sidePanel;
|
|
51945
52177
|
composer;
|
|
52178
|
+
spreadsheetRef = owl.useRef("spreadsheet");
|
|
51946
52179
|
_focusGrid;
|
|
51947
52180
|
keyDownMapping;
|
|
51948
52181
|
isViewportTooSmall = false;
|
|
@@ -51977,6 +52210,18 @@ class Spreadsheet extends owl.Component {
|
|
|
51977
52210
|
clipboard: this.env.clipboard || instantiateClipboard(),
|
|
51978
52211
|
startCellEdition: (content) => this.onGridComposerCellFocused(content),
|
|
51979
52212
|
});
|
|
52213
|
+
owl.useEffect(() => {
|
|
52214
|
+
/**
|
|
52215
|
+
* Only refocus the grid if the active element is not a child of the spreadsheet
|
|
52216
|
+
* (i.e. activeElement is outside of the spreadsheetRef component)
|
|
52217
|
+
* and spreadsheet is a child of that element. Anything else means that the focus
|
|
52218
|
+
* is on an element that needs to keep it.
|
|
52219
|
+
*/
|
|
52220
|
+
if (!this.spreadsheetRef.el.contains(document.activeElement) &&
|
|
52221
|
+
document.activeElement?.contains(this.spreadsheetRef.el)) {
|
|
52222
|
+
this.focusGrid();
|
|
52223
|
+
}
|
|
52224
|
+
}, () => [this.env.model.getters.getActiveSheetId()]);
|
|
51980
52225
|
owl.useExternalListener(window, "resize", () => this.render(true));
|
|
51981
52226
|
owl.useExternalListener(window, "beforeunload", this.unbindModelEvents.bind(this));
|
|
51982
52227
|
this.bindModelEvents();
|
|
@@ -52058,7 +52303,7 @@ class Spreadsheet extends owl.Component {
|
|
|
52058
52303
|
}
|
|
52059
52304
|
focusGrid() {
|
|
52060
52305
|
if (!this._focusGrid) {
|
|
52061
|
-
|
|
52306
|
+
return;
|
|
52062
52307
|
}
|
|
52063
52308
|
this._focusGrid();
|
|
52064
52309
|
}
|
|
@@ -55451,19 +55696,22 @@ class Model extends EventBus {
|
|
|
55451
55696
|
* Check if the given command is allowed by all the plugins and the history.
|
|
55452
55697
|
*/
|
|
55453
55698
|
checkDispatchAllowed(command) {
|
|
55454
|
-
|
|
55455
|
-
|
|
55699
|
+
const results = isCoreCommand(command)
|
|
55700
|
+
? this.checkDispatchAllowedCoreCommand(command)
|
|
55701
|
+
: this.checkDispatchAllowedLocalCommand(command);
|
|
55702
|
+
if (results.some((r) => r !== "Success" /* CommandResult.Success */)) {
|
|
55703
|
+
return new DispatchResult(results.flat());
|
|
55456
55704
|
}
|
|
55457
|
-
return
|
|
55705
|
+
return DispatchResult.Success;
|
|
55458
55706
|
}
|
|
55459
55707
|
checkDispatchAllowedCoreCommand(command) {
|
|
55460
55708
|
const results = this.corePlugins.map((handler) => handler.allowDispatch(command));
|
|
55461
55709
|
results.push(this.range.allowDispatch(command));
|
|
55462
|
-
return
|
|
55710
|
+
return results;
|
|
55463
55711
|
}
|
|
55464
55712
|
checkDispatchAllowedLocalCommand(command) {
|
|
55465
55713
|
const results = this.uiHandlers.map((handler) => handler.allowDispatch(command));
|
|
55466
|
-
return
|
|
55714
|
+
return results;
|
|
55467
55715
|
}
|
|
55468
55716
|
finalize() {
|
|
55469
55717
|
this.status = 3 /* Status.Finalizing */;
|
|
@@ -55758,6 +56006,7 @@ const components = {
|
|
|
55758
56006
|
FigureComponent,
|
|
55759
56007
|
Menu,
|
|
55760
56008
|
SelectionInput,
|
|
56009
|
+
ValidationMessages,
|
|
55761
56010
|
};
|
|
55762
56011
|
const hooks = {
|
|
55763
56012
|
useDragAndDropListItems,
|
|
@@ -55810,6 +56059,6 @@ exports.setTranslationMethod = setTranslationMethod;
|
|
|
55810
56059
|
exports.tokenize = tokenize;
|
|
55811
56060
|
|
|
55812
56061
|
|
|
55813
|
-
__info__.version = "17.1.0-alpha.
|
|
55814
|
-
__info__.date = "2023-
|
|
55815
|
-
__info__.hash = "
|
|
56062
|
+
__info__.version = "17.1.0-alpha.5";
|
|
56063
|
+
__info__.date = "2023-12-05T09:51:40.034Z";
|
|
56064
|
+
__info__.hash = "c2823eb";
|