@odoo/o-spreadsheet 17.1.0-alpha.2 → 17.1.0-alpha.4
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 +818 -668
- package/dist/o-spreadsheet.d.ts +169 -191
- package/dist/o-spreadsheet.esm.js +817 -669
- package/dist/o-spreadsheet.iife.js +818 -668
- package/dist/o-spreadsheet.iife.min.js +322 -348
- package/dist/o_spreadsheet.xml +99 -61
- 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-11-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 17.1.0-alpha.4
|
|
6
|
+
* @date 2023-11-24T13:12:24.882Z
|
|
7
|
+
* @hash 255821b
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { Component, useRef, onMounted, useEffect, onWillPatch, useState, onWillUpdateProps, onPatched, useComponent, useExternalListener, onWillUnmount, onWillStart, xml, useChildSubEnv, useSubEnv, markRaw } from '@odoo/owl';
|
|
@@ -227,7 +227,6 @@ const DEFAULT_CELL_HEIGHT = 23;
|
|
|
227
227
|
const SCROLLBAR_WIDTH = 15;
|
|
228
228
|
const AUTOFILL_EDGE_LENGTH = 8;
|
|
229
229
|
const ICON_EDGE_LENGTH = 18;
|
|
230
|
-
const UNHIDE_ICON_EDGE_LENGTH = 14;
|
|
231
230
|
const MIN_CF_ICON_MARGIN = 4;
|
|
232
231
|
const MIN_CELL_TEXT_MARGIN = 4;
|
|
233
232
|
const CF_ICON_EDGE_LENGTH = 15;
|
|
@@ -691,8 +690,7 @@ function removeFalsyAttributes(obj) {
|
|
|
691
690
|
*
|
|
692
691
|
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes
|
|
693
692
|
*/
|
|
694
|
-
const
|
|
695
|
-
" ",
|
|
693
|
+
const whiteSpaceSpecialCharacters = [
|
|
696
694
|
"\t",
|
|
697
695
|
"\f",
|
|
698
696
|
"\v",
|
|
@@ -707,8 +705,7 @@ const whiteSpaceCharacters = [
|
|
|
707
705
|
String.fromCharCode(parseInt("3000", 16)),
|
|
708
706
|
String.fromCharCode(parseInt("feff", 16)),
|
|
709
707
|
];
|
|
710
|
-
const whiteSpaceRegexp = new RegExp(
|
|
711
|
-
const newLineRegex = /\r\n|\r|\n/g;
|
|
708
|
+
const whiteSpaceRegexp = new RegExp(whiteSpaceSpecialCharacters.join("|") + "|(\r\n|\r|\n)", "g");
|
|
712
709
|
/**
|
|
713
710
|
* Replace all the special spaces in a string (non-breaking, tabs, ...) by normal spaces, and all the
|
|
714
711
|
* different newlines types by \n.
|
|
@@ -716,9 +713,9 @@ const newLineRegex = /\r\n|\r|\n/g;
|
|
|
716
713
|
function replaceSpecialSpaces(text) {
|
|
717
714
|
if (!text)
|
|
718
715
|
return "";
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
return text;
|
|
716
|
+
if (!whiteSpaceRegexp.test(text))
|
|
717
|
+
return text;
|
|
718
|
+
return text.replace(whiteSpaceRegexp, (match, newLine) => (newLine ? NEWLINE : " "));
|
|
722
719
|
}
|
|
723
720
|
/**
|
|
724
721
|
* Determine if the numbers are consecutive.
|
|
@@ -2060,6 +2057,7 @@ var CommandResult;
|
|
|
2060
2057
|
CommandResult["InvalidNumberOfCriterionValues"] = "InvalidNumberOfCriterionValues";
|
|
2061
2058
|
CommandResult["BlockingValidationRule"] = "BlockingValidationRule";
|
|
2062
2059
|
CommandResult["InvalidCopyPasteSelection"] = "InvalidCopyPasteSelection";
|
|
2060
|
+
CommandResult["NoChanges"] = "NoChanges";
|
|
2063
2061
|
})(CommandResult || (CommandResult = {}));
|
|
2064
2062
|
|
|
2065
2063
|
const DEFAULT_LOCALES = [
|
|
@@ -2189,12 +2187,12 @@ function toString(value) {
|
|
|
2189
2187
|
}
|
|
2190
2188
|
}
|
|
2191
2189
|
/** Normalize string by setting it to lowercase and replacing accent letters with plain letters */
|
|
2192
|
-
function normalizeString(str) {
|
|
2190
|
+
const normalizeString = memoize(function normalizeString(str) {
|
|
2193
2191
|
return str
|
|
2194
2192
|
.toLowerCase()
|
|
2195
2193
|
.normalize("NFD")
|
|
2196
2194
|
.replace(/[\u0300-\u036f]/g, "");
|
|
2197
|
-
}
|
|
2195
|
+
});
|
|
2198
2196
|
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);
|
|
2199
2197
|
function toBoolean(value) {
|
|
2200
2198
|
switch (typeof value) {
|
|
@@ -3427,11 +3425,18 @@ function isSingleCellReference(xc) {
|
|
|
3427
3425
|
return singleCellReference.test(xc);
|
|
3428
3426
|
}
|
|
3429
3427
|
function splitReference(ref) {
|
|
3428
|
+
if (!ref.includes("!")) {
|
|
3429
|
+
return { xc: ref };
|
|
3430
|
+
}
|
|
3430
3431
|
const parts = ref.split("!");
|
|
3431
3432
|
const xc = parts.pop();
|
|
3432
3433
|
const sheetName = getUnquotedSheetName(parts.join("!")) || undefined;
|
|
3433
3434
|
return { sheetName, xc };
|
|
3434
3435
|
}
|
|
3436
|
+
/** Return a reference SheetName!xc from the given arguments */
|
|
3437
|
+
function getFullReference(sheetName, xc) {
|
|
3438
|
+
return sheetName !== undefined ? `${getCanonicalSheetName(sheetName)}!${xc}` : xc;
|
|
3439
|
+
}
|
|
3435
3440
|
|
|
3436
3441
|
/**
|
|
3437
3442
|
* Convert from a cartesian reference to a Zone
|
|
@@ -4540,14 +4545,14 @@ function drawDecoratedText(context, text, position, underline = false, strikethr
|
|
|
4540
4545
|
switch (context.textBaseline) {
|
|
4541
4546
|
case "top":
|
|
4542
4547
|
underlineY += boxHeight - 2 * strokeWidth;
|
|
4543
|
-
strikeY += boxHeight -
|
|
4548
|
+
strikeY += boxHeight / 2 - strokeWidth;
|
|
4544
4549
|
break;
|
|
4545
4550
|
case "middle":
|
|
4546
4551
|
underlineY += boxHeight / 2 - strokeWidth;
|
|
4547
4552
|
break;
|
|
4548
4553
|
case "alphabetic":
|
|
4549
4554
|
underlineY += 2 * strokeWidth;
|
|
4550
|
-
strikeY -=
|
|
4555
|
+
strikeY -= 3 * strokeWidth;
|
|
4551
4556
|
break;
|
|
4552
4557
|
case "bottom":
|
|
4553
4558
|
underlineY = y;
|
|
@@ -4610,6 +4615,7 @@ function createAction(item) {
|
|
|
4610
4615
|
const children = item.children;
|
|
4611
4616
|
const description = item.description;
|
|
4612
4617
|
const icon = item.icon;
|
|
4618
|
+
const secondaryIcon = item.secondaryIcon;
|
|
4613
4619
|
return {
|
|
4614
4620
|
id: item.id || uuidGenerator$2.uuidv4(),
|
|
4615
4621
|
name: typeof name === "function" ? name : () => name,
|
|
@@ -4628,6 +4634,7 @@ function createAction(item) {
|
|
|
4628
4634
|
isReadonlyAllowed: item.isReadonlyAllowed || false,
|
|
4629
4635
|
separator: item.separator || false,
|
|
4630
4636
|
icon: typeof icon === "function" ? icon : () => icon || "",
|
|
4637
|
+
secondaryIcon: typeof secondaryIcon === "function" ? secondaryIcon : () => secondaryIcon || "",
|
|
4631
4638
|
description: typeof description === "function" ? description : () => description || "",
|
|
4632
4639
|
textColor: item.textColor,
|
|
4633
4640
|
sequence: item.sequence || 0,
|
|
@@ -5966,7 +5973,7 @@ autofillModifiersRegistry
|
|
|
5966
5973
|
return { cellData: {} };
|
|
5967
5974
|
}
|
|
5968
5975
|
const sheetId = data.sheetId;
|
|
5969
|
-
const content = getters.getTranslatedCellFormula(sheetId, x, y, cell.compiledFormula
|
|
5976
|
+
const content = getters.getTranslatedCellFormula(sheetId, x, y, cell.compiledFormula);
|
|
5970
5977
|
return {
|
|
5971
5978
|
cellData: {
|
|
5972
5979
|
border: data.border,
|
|
@@ -6983,11 +6990,9 @@ css /* scss */ `
|
|
|
6983
6990
|
padding: ${MENU_VERTICAL_PADDING}px 0px;
|
|
6984
6991
|
width: ${MENU_WIDTH}px;
|
|
6985
6992
|
box-sizing: border-box !important;
|
|
6993
|
+
user-select: none;
|
|
6986
6994
|
|
|
6987
6995
|
.o-menu-item {
|
|
6988
|
-
display: flex;
|
|
6989
|
-
justify-content: space-between;
|
|
6990
|
-
align-items: center;
|
|
6991
6996
|
box-sizing: border-box;
|
|
6992
6997
|
height: ${MENU_ITEM_HEIGHT}px;
|
|
6993
6998
|
padding: ${MENU_ITEM_PADDING_VERTICAL}px ${MENU_ITEM_PADDING_HORIZONTAL}px;
|
|
@@ -6998,20 +7003,12 @@ css /* scss */ `
|
|
|
6998
7003
|
min-width: 40%;
|
|
6999
7004
|
}
|
|
7000
7005
|
|
|
7001
|
-
&.o-menu-root {
|
|
7002
|
-
display: flex;
|
|
7003
|
-
justify-content: space-between;
|
|
7004
|
-
}
|
|
7005
|
-
|
|
7006
7006
|
.o-menu-item-icon {
|
|
7007
7007
|
display: inline-block;
|
|
7008
7008
|
margin: 0px 8px 0px 0px;
|
|
7009
7009
|
width: ${MENU_ITEM_HEIGHT - 2 * MENU_ITEM_PADDING_VERTICAL}px;
|
|
7010
7010
|
line-height: ${MENU_ITEM_HEIGHT - 2 * MENU_ITEM_PADDING_VERTICAL}px;
|
|
7011
7011
|
}
|
|
7012
|
-
.o-menu-item-root {
|
|
7013
|
-
width: 10px;
|
|
7014
|
-
}
|
|
7015
7012
|
|
|
7016
7013
|
&:not(.disabled) {
|
|
7017
7014
|
&:hover,
|
|
@@ -7354,7 +7351,7 @@ function tokenize(str, locale = DEFAULT_LOCALE) {
|
|
|
7354
7351
|
return result;
|
|
7355
7352
|
}
|
|
7356
7353
|
function tokenizeDebugger(chars) {
|
|
7357
|
-
if (chars.current
|
|
7354
|
+
if (chars.current === "?") {
|
|
7358
7355
|
chars.shift();
|
|
7359
7356
|
return { type: "DEBUGGER", value: "?" };
|
|
7360
7357
|
}
|
|
@@ -7365,7 +7362,7 @@ const misc$1 = {
|
|
|
7365
7362
|
")": "RIGHT_PAREN",
|
|
7366
7363
|
};
|
|
7367
7364
|
function tokenizeMisc(chars) {
|
|
7368
|
-
if (chars.current
|
|
7365
|
+
if (chars.current in misc$1) {
|
|
7369
7366
|
const value = chars.shift();
|
|
7370
7367
|
const type = misc$1[value];
|
|
7371
7368
|
return { type, value };
|
|
@@ -7373,7 +7370,7 @@ function tokenizeMisc(chars) {
|
|
|
7373
7370
|
return null;
|
|
7374
7371
|
}
|
|
7375
7372
|
function tokenizeArgsSeparator(chars, locale) {
|
|
7376
|
-
if (chars.current
|
|
7373
|
+
if (chars.current === locale.formulaArgSeparator) {
|
|
7377
7374
|
const value = chars.shift();
|
|
7378
7375
|
const type = "ARG_SEPARATOR";
|
|
7379
7376
|
return { type, value };
|
|
@@ -7398,14 +7395,13 @@ function tokenizeNumber(chars, locale) {
|
|
|
7398
7395
|
return null;
|
|
7399
7396
|
}
|
|
7400
7397
|
function tokenizeString(chars) {
|
|
7401
|
-
if (chars.current
|
|
7398
|
+
if (chars.current === '"') {
|
|
7402
7399
|
const startChar = chars.shift();
|
|
7403
7400
|
let letters = startChar;
|
|
7404
|
-
while (chars.current()
|
|
7405
|
-
(chars.current() !== startChar || letters[letters.length - 1] === "\\")) {
|
|
7401
|
+
while (chars.current && (chars.current !== startChar || letters[letters.length - 1] === "\\")) {
|
|
7406
7402
|
letters += chars.shift();
|
|
7407
7403
|
}
|
|
7408
|
-
if (chars.current
|
|
7404
|
+
if (chars.current === '"') {
|
|
7409
7405
|
letters += chars.shift();
|
|
7410
7406
|
}
|
|
7411
7407
|
return {
|
|
@@ -7432,14 +7428,14 @@ function tokenizeSymbol(chars) {
|
|
|
7432
7428
|
let result = "";
|
|
7433
7429
|
// there are two main cases to manage: either something which starts with
|
|
7434
7430
|
// a ', like 'Sheet 2'A2, or a word-like element.
|
|
7435
|
-
if (chars.current
|
|
7431
|
+
if (chars.current === "'") {
|
|
7436
7432
|
let lastChar = chars.shift();
|
|
7437
7433
|
result += lastChar;
|
|
7438
|
-
while (chars.current
|
|
7434
|
+
while (chars.current) {
|
|
7439
7435
|
lastChar = chars.shift();
|
|
7440
7436
|
result += lastChar;
|
|
7441
7437
|
if (lastChar === "'") {
|
|
7442
|
-
if (chars.current
|
|
7438
|
+
if (chars.current && chars.current === "'") {
|
|
7443
7439
|
lastChar = chars.shift();
|
|
7444
7440
|
result += lastChar;
|
|
7445
7441
|
}
|
|
@@ -7455,7 +7451,7 @@ function tokenizeSymbol(chars) {
|
|
|
7455
7451
|
};
|
|
7456
7452
|
}
|
|
7457
7453
|
}
|
|
7458
|
-
while (chars.current
|
|
7454
|
+
while (chars.current && separatorRegexp.test(chars.current)) {
|
|
7459
7455
|
result += chars.shift();
|
|
7460
7456
|
}
|
|
7461
7457
|
if (result.length) {
|
|
@@ -7470,14 +7466,14 @@ function tokenizeSymbol(chars) {
|
|
|
7470
7466
|
}
|
|
7471
7467
|
function tokenizeSpace(chars) {
|
|
7472
7468
|
let length = 0;
|
|
7473
|
-
while (chars.current
|
|
7469
|
+
while (chars.current === NEWLINE) {
|
|
7474
7470
|
length++;
|
|
7475
7471
|
chars.shift();
|
|
7476
7472
|
}
|
|
7477
7473
|
if (length) {
|
|
7478
7474
|
return { type: "SPACE", value: NEWLINE.repeat(length) };
|
|
7479
7475
|
}
|
|
7480
|
-
while (chars.current
|
|
7476
|
+
while (chars.current === " ") {
|
|
7481
7477
|
length++;
|
|
7482
7478
|
chars.shift();
|
|
7483
7479
|
}
|
|
@@ -7496,17 +7492,20 @@ function tokenizeInvalidRange(chars) {
|
|
|
7496
7492
|
class TokenizingChars {
|
|
7497
7493
|
text;
|
|
7498
7494
|
currentIndex = 0;
|
|
7495
|
+
current;
|
|
7499
7496
|
constructor(text) {
|
|
7500
7497
|
this.text = text;
|
|
7501
|
-
|
|
7502
|
-
current() {
|
|
7503
|
-
return this.text[this.currentIndex];
|
|
7498
|
+
this.current = text[0];
|
|
7504
7499
|
}
|
|
7505
7500
|
shift() {
|
|
7506
|
-
|
|
7501
|
+
const current = this.current;
|
|
7502
|
+
const next = this.text[++this.currentIndex];
|
|
7503
|
+
this.current = next;
|
|
7504
|
+
return current;
|
|
7507
7505
|
}
|
|
7508
7506
|
advanceBy(length) {
|
|
7509
7507
|
this.currentIndex += length;
|
|
7508
|
+
this.current = this.text[this.currentIndex];
|
|
7510
7509
|
}
|
|
7511
7510
|
isOver() {
|
|
7512
7511
|
return this.currentIndex >= this.text.length;
|
|
@@ -10718,6 +10717,17 @@ const SELECTION_CONTAINS_FILTER = (env) => {
|
|
|
10718
10717
|
const IS_ONLY_ONE_RANGE = (env) => {
|
|
10719
10718
|
return env.model.getters.getSelectedZones().length === 1;
|
|
10720
10719
|
};
|
|
10720
|
+
const CAN_INSERT_HEADER = (env, dimension) => {
|
|
10721
|
+
if (!IS_ONLY_ONE_RANGE(env)) {
|
|
10722
|
+
return false;
|
|
10723
|
+
}
|
|
10724
|
+
const activeHeaders = dimension === "COL" ? env.model.getters.getActiveCols() : env.model.getters.getActiveRows();
|
|
10725
|
+
const ortogonalActiveHeaders = dimension === "COL" ? env.model.getters.getActiveRows() : env.model.getters.getActiveCols();
|
|
10726
|
+
const sheetId = env.model.getters.getActiveSheetId();
|
|
10727
|
+
const zone = env.model.getters.getSelectedZone();
|
|
10728
|
+
const allSheetSelected = isEqual(zone, env.model.getters.getSheetZone(sheetId));
|
|
10729
|
+
return isConsecutive(activeHeaders) && (ortogonalActiveHeaders.size === 0 || allSheetSelected);
|
|
10730
|
+
};
|
|
10721
10731
|
|
|
10722
10732
|
const undo = {
|
|
10723
10733
|
name: _t("Undo"),
|
|
@@ -11299,7 +11309,7 @@ const EXPAND = {
|
|
|
11299
11309
|
) {
|
|
11300
11310
|
const _array = toMatrix(arg);
|
|
11301
11311
|
const _nbRows = toInteger(rows?.value, this.locale);
|
|
11302
|
-
const _nbColumns = columns !== undefined ? toInteger(columns.value, this.
|
|
11312
|
+
const _nbColumns = columns !== undefined ? toInteger(columns.value, this.locale) : _array.length;
|
|
11303
11313
|
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()));
|
|
11304
11314
|
assert(() => _nbColumns >= _array.length, _t("The columns arguments (%s) must be greater or equal than the number of columns of the array.", _nbColumns.toString()));
|
|
11305
11315
|
return generateMatrix(_nbColumns, _nbRows, (col, row) => col >= _array.length || row >= _array[col].length ? padWith : _array[col][row]);
|
|
@@ -11788,6 +11798,10 @@ var misc = /*#__PURE__*/Object.freeze({
|
|
|
11788
11798
|
FORMAT_LARGE_NUMBER: FORMAT_LARGE_NUMBER
|
|
11789
11799
|
});
|
|
11790
11800
|
|
|
11801
|
+
function sum(values, locale) {
|
|
11802
|
+
return reduceNumbers(values, (acc, a) => acc + a, 0, locale);
|
|
11803
|
+
}
|
|
11804
|
+
|
|
11791
11805
|
const DEFAULT_FACTOR = 1;
|
|
11792
11806
|
const DEFAULT_MODE = 0;
|
|
11793
11807
|
const DEFAULT_PLACES = 0;
|
|
@@ -12739,7 +12753,7 @@ const SUM = {
|
|
|
12739
12753
|
return isMatrix(value1) ? value1[0][0]?.format : value1?.format;
|
|
12740
12754
|
},
|
|
12741
12755
|
compute: function (...values) {
|
|
12742
|
-
return
|
|
12756
|
+
return sum(values, this.locale);
|
|
12743
12757
|
},
|
|
12744
12758
|
isExported: true,
|
|
12745
12759
|
};
|
|
@@ -12908,6 +12922,44 @@ function assertSameNumberOfElements(...args) {
|
|
|
12908
12922
|
const dims = args[0].length;
|
|
12909
12923
|
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())));
|
|
12910
12924
|
}
|
|
12925
|
+
function average(values, locale) {
|
|
12926
|
+
let count = 0;
|
|
12927
|
+
const sum = reduceNumbers(values, (acc, a) => {
|
|
12928
|
+
count += 1;
|
|
12929
|
+
return acc + a;
|
|
12930
|
+
}, 0, locale);
|
|
12931
|
+
assert(() => count !== 0, _t("Evaluation of function [[FUNCTION_NAME]] caused a divide by zero error."));
|
|
12932
|
+
return sum / count;
|
|
12933
|
+
}
|
|
12934
|
+
function countNumbers(values, locale) {
|
|
12935
|
+
let count = 0;
|
|
12936
|
+
for (let n of values) {
|
|
12937
|
+
if (isMatrix(n)) {
|
|
12938
|
+
for (let i of n) {
|
|
12939
|
+
for (let j of i) {
|
|
12940
|
+
if (typeof j === "number") {
|
|
12941
|
+
count += 1;
|
|
12942
|
+
}
|
|
12943
|
+
}
|
|
12944
|
+
}
|
|
12945
|
+
}
|
|
12946
|
+
else if (typeof n !== "string" || isNumber(n, locale) || parseDateTime(n, locale)) {
|
|
12947
|
+
count += 1;
|
|
12948
|
+
}
|
|
12949
|
+
}
|
|
12950
|
+
return count;
|
|
12951
|
+
}
|
|
12952
|
+
function countAny(values) {
|
|
12953
|
+
return reduceAny(values, (acc, a) => (a !== undefined && a !== null ? acc + 1 : acc), 0);
|
|
12954
|
+
}
|
|
12955
|
+
function max(values, locale) {
|
|
12956
|
+
const result = reduceNumbers(values, (acc, a) => (acc < a ? a : acc), -Infinity, locale);
|
|
12957
|
+
return result === -Infinity ? 0 : result;
|
|
12958
|
+
}
|
|
12959
|
+
function min(values, locale) {
|
|
12960
|
+
const result = reduceNumbers(values, (acc, a) => (a < acc ? a : acc), Infinity, locale);
|
|
12961
|
+
return result === Infinity ? 0 : result;
|
|
12962
|
+
}
|
|
12911
12963
|
|
|
12912
12964
|
function filterAndFlatData(dataY, dataX) {
|
|
12913
12965
|
const _flatDataY = [];
|
|
@@ -13178,13 +13230,7 @@ const AVERAGE = {
|
|
|
13178
13230
|
return isMatrix(value1) ? value1[0][0]?.format : value1?.format;
|
|
13179
13231
|
},
|
|
13180
13232
|
compute: function (...values) {
|
|
13181
|
-
|
|
13182
|
-
const sum = reduceNumbers(values, (acc, a) => {
|
|
13183
|
-
count += 1;
|
|
13184
|
-
return acc + a;
|
|
13185
|
-
}, 0, this.locale);
|
|
13186
|
-
assert(() => count !== 0, _t("Evaluation of function [[FUNCTION_NAME]] caused a divide by zero error."));
|
|
13187
|
-
return sum / count;
|
|
13233
|
+
return average(values, this.locale);
|
|
13188
13234
|
},
|
|
13189
13235
|
isExported: true,
|
|
13190
13236
|
};
|
|
@@ -13342,24 +13388,7 @@ const COUNT = {
|
|
|
13342
13388
|
],
|
|
13343
13389
|
returns: ["NUMBER"],
|
|
13344
13390
|
compute: function (...values) {
|
|
13345
|
-
|
|
13346
|
-
for (let n of values) {
|
|
13347
|
-
if (isMatrix(n)) {
|
|
13348
|
-
for (let i of n) {
|
|
13349
|
-
for (let j of i) {
|
|
13350
|
-
if (typeof j === "number") {
|
|
13351
|
-
count += 1;
|
|
13352
|
-
}
|
|
13353
|
-
}
|
|
13354
|
-
}
|
|
13355
|
-
}
|
|
13356
|
-
else if (typeof n !== "string" ||
|
|
13357
|
-
isNumber(n, this.locale) ||
|
|
13358
|
-
parseDateTime(n, this.locale)) {
|
|
13359
|
-
count += 1;
|
|
13360
|
-
}
|
|
13361
|
-
}
|
|
13362
|
-
return count;
|
|
13391
|
+
return countNumbers(values, this.locale);
|
|
13363
13392
|
},
|
|
13364
13393
|
isExported: true,
|
|
13365
13394
|
};
|
|
@@ -13374,7 +13403,7 @@ const COUNTA = {
|
|
|
13374
13403
|
],
|
|
13375
13404
|
returns: ["NUMBER"],
|
|
13376
13405
|
compute: function (...values) {
|
|
13377
|
-
return
|
|
13406
|
+
return countAny(values);
|
|
13378
13407
|
},
|
|
13379
13408
|
isExported: true,
|
|
13380
13409
|
};
|
|
@@ -13604,8 +13633,7 @@ const MAX = {
|
|
|
13604
13633
|
return isMatrix(value1) ? value1[0][0]?.format : value1?.format;
|
|
13605
13634
|
},
|
|
13606
13635
|
compute: function (...values) {
|
|
13607
|
-
|
|
13608
|
-
return result === -Infinity ? 0 : result;
|
|
13636
|
+
return max(values, this.locale);
|
|
13609
13637
|
},
|
|
13610
13638
|
isExported: true,
|
|
13611
13639
|
};
|
|
@@ -13692,8 +13720,7 @@ const MIN = {
|
|
|
13692
13720
|
return isMatrix(value1) ? value1[0][0]?.format : value1?.format;
|
|
13693
13721
|
},
|
|
13694
13722
|
compute: function (...values) {
|
|
13695
|
-
|
|
13696
|
-
return result === Infinity ? 0 : result;
|
|
13723
|
+
return min(values, this.locale);
|
|
13697
13724
|
},
|
|
13698
13725
|
isExported: true,
|
|
13699
13726
|
};
|
|
@@ -17864,6 +17891,149 @@ var financial = /*#__PURE__*/Object.freeze({
|
|
|
17864
17891
|
YIELDMAT: YIELDMAT
|
|
17865
17892
|
});
|
|
17866
17893
|
|
|
17894
|
+
/**
|
|
17895
|
+
* Change the reference types inside the given token, if the token represent a range or a cell
|
|
17896
|
+
*
|
|
17897
|
+
* Eg. :
|
|
17898
|
+
* A1 => $A$1 => A$1 => $A1 => A1
|
|
17899
|
+
* A1:$B$1 => $A$1:B$1 => A$1:$B1 => $A1:B1 => A1:$B$1
|
|
17900
|
+
*/
|
|
17901
|
+
function loopThroughReferenceType(token) {
|
|
17902
|
+
if (token.type !== "REFERENCE")
|
|
17903
|
+
return token;
|
|
17904
|
+
const { xc, sheetName } = splitReference(token.value);
|
|
17905
|
+
const [left, right] = xc.split(":");
|
|
17906
|
+
const updatedLeft = getTokenNextReferenceType(left);
|
|
17907
|
+
const updatedRight = right ? `:${getTokenNextReferenceType(right)}` : "";
|
|
17908
|
+
return { ...token, value: getFullReference(sheetName, updatedLeft + updatedRight) };
|
|
17909
|
+
}
|
|
17910
|
+
/**
|
|
17911
|
+
* Get a new token with a changed type of reference from the given cell token symbol.
|
|
17912
|
+
* Undefined behavior if given a token other than a cell or if the Xc contains a sheet reference
|
|
17913
|
+
*
|
|
17914
|
+
* A1 => $A$1 => A$1 => $A1 => A1
|
|
17915
|
+
*/
|
|
17916
|
+
function getTokenNextReferenceType(xc) {
|
|
17917
|
+
switch (getReferenceType(xc)) {
|
|
17918
|
+
case "none":
|
|
17919
|
+
xc = setXcToFixedReferenceType(xc, "colrow");
|
|
17920
|
+
break;
|
|
17921
|
+
case "colrow":
|
|
17922
|
+
xc = setXcToFixedReferenceType(xc, "row");
|
|
17923
|
+
break;
|
|
17924
|
+
case "row":
|
|
17925
|
+
xc = setXcToFixedReferenceType(xc, "col");
|
|
17926
|
+
break;
|
|
17927
|
+
case "col":
|
|
17928
|
+
xc = setXcToFixedReferenceType(xc, "none");
|
|
17929
|
+
break;
|
|
17930
|
+
}
|
|
17931
|
+
return xc;
|
|
17932
|
+
}
|
|
17933
|
+
/**
|
|
17934
|
+
* Returns the given XC with the given reference type. The XC string should not contain a sheet name.
|
|
17935
|
+
*/
|
|
17936
|
+
function setXcToFixedReferenceType(xc, referenceType) {
|
|
17937
|
+
if (xc.includes("!")) {
|
|
17938
|
+
throw new Error("The given XC should not contain a sheet name");
|
|
17939
|
+
}
|
|
17940
|
+
xc = xc.replace(/\$/g, "");
|
|
17941
|
+
let indexOfNumber;
|
|
17942
|
+
switch (referenceType) {
|
|
17943
|
+
case "col":
|
|
17944
|
+
return "$" + xc;
|
|
17945
|
+
case "row":
|
|
17946
|
+
indexOfNumber = xc.search(/[0-9]/);
|
|
17947
|
+
return xc.slice(0, indexOfNumber) + "$" + xc.slice(indexOfNumber);
|
|
17948
|
+
case "colrow":
|
|
17949
|
+
indexOfNumber = xc.search(/[0-9]/);
|
|
17950
|
+
xc = xc.slice(0, indexOfNumber) + "$" + xc.slice(indexOfNumber);
|
|
17951
|
+
return "$" + xc;
|
|
17952
|
+
case "none":
|
|
17953
|
+
return xc;
|
|
17954
|
+
}
|
|
17955
|
+
}
|
|
17956
|
+
/**
|
|
17957
|
+
* Return the type of reference used in the given XC of a cell.
|
|
17958
|
+
* Undefined behavior if the XC have a sheet reference
|
|
17959
|
+
*/
|
|
17960
|
+
function getReferenceType(xcCell) {
|
|
17961
|
+
if (isColAndRowFixed(xcCell)) {
|
|
17962
|
+
return "colrow";
|
|
17963
|
+
}
|
|
17964
|
+
else if (isColFixed(xcCell)) {
|
|
17965
|
+
return "col";
|
|
17966
|
+
}
|
|
17967
|
+
else if (isRowFixed(xcCell)) {
|
|
17968
|
+
return "row";
|
|
17969
|
+
}
|
|
17970
|
+
return "none";
|
|
17971
|
+
}
|
|
17972
|
+
function isColFixed(xc) {
|
|
17973
|
+
return xc.startsWith("$");
|
|
17974
|
+
}
|
|
17975
|
+
function isRowFixed(xc) {
|
|
17976
|
+
return xc.includes("$", 1);
|
|
17977
|
+
}
|
|
17978
|
+
function isColAndRowFixed(xc) {
|
|
17979
|
+
return xc.startsWith("$") && xc.length > 1 && xc.slice(1).includes("$");
|
|
17980
|
+
}
|
|
17981
|
+
|
|
17982
|
+
// -----------------------------------------------------------------------------
|
|
17983
|
+
// CELL
|
|
17984
|
+
// -----------------------------------------------------------------------------
|
|
17985
|
+
// NOTE: missing from Excel: "color", "filename", "parentheses", "prefix", "protect" and "width"
|
|
17986
|
+
const CELL_INFO_TYPES = ["address", "col", "contents", "format", "row", "type"];
|
|
17987
|
+
const CELL = {
|
|
17988
|
+
description: _t("Gets information about a cell."),
|
|
17989
|
+
args: [
|
|
17990
|
+
arg("info_type (string)", _t("The type of information requested. Can be one of %s", CELL_INFO_TYPES.join(", "))),
|
|
17991
|
+
arg("reference (meta)", _t("The reference to the cell.")),
|
|
17992
|
+
],
|
|
17993
|
+
returns: ["ANY"],
|
|
17994
|
+
compute: function (info, reference) {
|
|
17995
|
+
const _info = toString(info).toLowerCase();
|
|
17996
|
+
assert(() => CELL_INFO_TYPES.includes(_info), _t("The info_type should be one of %s.", CELL_INFO_TYPES.join(", ")));
|
|
17997
|
+
const sheetId = this.__originSheetId;
|
|
17998
|
+
const topLeftReference = reference.includes(":") ? reference.split(":")[0] : reference;
|
|
17999
|
+
let { sheetName, xc } = splitReference(topLeftReference);
|
|
18000
|
+
// only put the sheet name if the referenced range is in another sheet than the cell the formula is on
|
|
18001
|
+
sheetName = sheetName === this.getters.getSheetName(sheetId) ? undefined : sheetName;
|
|
18002
|
+
const fixedRef = getFullReference(sheetName, setXcToFixedReferenceType(xc, "colrow"));
|
|
18003
|
+
const range = this.getters.getRangeFromSheetXC(sheetId, fixedRef);
|
|
18004
|
+
switch (_info) {
|
|
18005
|
+
case "address":
|
|
18006
|
+
return this.getters.getRangeString(range, sheetId);
|
|
18007
|
+
case "col":
|
|
18008
|
+
return range.zone.left + 1;
|
|
18009
|
+
case "contents": {
|
|
18010
|
+
const position = { sheetId: range.sheetId, col: range.zone.left, row: range.zone.top };
|
|
18011
|
+
return this.getters.getEvaluatedCell(position).value;
|
|
18012
|
+
}
|
|
18013
|
+
case "format": {
|
|
18014
|
+
const position = { sheetId: range.sheetId, col: range.zone.left, row: range.zone.top };
|
|
18015
|
+
return this.getters.getEvaluatedCell(position).format || "";
|
|
18016
|
+
}
|
|
18017
|
+
case "row":
|
|
18018
|
+
return range.zone.top + 1;
|
|
18019
|
+
case "type": {
|
|
18020
|
+
const position = { sheetId: range.sheetId, col: range.zone.left, row: range.zone.top };
|
|
18021
|
+
const type = this.getters.getEvaluatedCell(position).type;
|
|
18022
|
+
if (type === CellValueType.empty) {
|
|
18023
|
+
return "b"; // blank
|
|
18024
|
+
}
|
|
18025
|
+
else if (type === CellValueType.text) {
|
|
18026
|
+
return "l"; // label
|
|
18027
|
+
}
|
|
18028
|
+
else {
|
|
18029
|
+
return "v"; // value
|
|
18030
|
+
}
|
|
18031
|
+
}
|
|
18032
|
+
}
|
|
18033
|
+
return "";
|
|
18034
|
+
},
|
|
18035
|
+
isExported: true,
|
|
18036
|
+
};
|
|
17867
18037
|
// -----------------------------------------------------------------------------
|
|
17868
18038
|
// ISERR
|
|
17869
18039
|
// -----------------------------------------------------------------------------
|
|
@@ -18019,6 +18189,7 @@ const NA = {
|
|
|
18019
18189
|
|
|
18020
18190
|
var info = /*#__PURE__*/Object.freeze({
|
|
18021
18191
|
__proto__: null,
|
|
18192
|
+
CELL: CELL,
|
|
18022
18193
|
ISBLANK: ISBLANK,
|
|
18023
18194
|
ISERR: ISERR,
|
|
18024
18195
|
ISERROR: ISERROR,
|
|
@@ -18310,7 +18481,7 @@ const ADDRESS = {
|
|
|
18310
18481
|
cellReference = rowPart + colPart;
|
|
18311
18482
|
}
|
|
18312
18483
|
if (sheet !== undefined) {
|
|
18313
|
-
return
|
|
18484
|
+
return getFullReference(toString(sheet), cellReference);
|
|
18314
18485
|
}
|
|
18315
18486
|
return cellReference;
|
|
18316
18487
|
},
|
|
@@ -18326,7 +18497,7 @@ const COLUMN = {
|
|
|
18326
18497
|
],
|
|
18327
18498
|
returns: ["NUMBER"],
|
|
18328
18499
|
compute: function (cellReference) {
|
|
18329
|
-
const _cellReference = cellReference || this.__originCellXC
|
|
18500
|
+
const _cellReference = cellReference || this.__originCellXC();
|
|
18330
18501
|
assert(() => !!_cellReference, "In this context, the function [[FUNCTION_NAME]] needs to have a cell or range in parameter.");
|
|
18331
18502
|
const zone = toZone(_cellReference);
|
|
18332
18503
|
return zone.left + 1;
|
|
@@ -18493,7 +18664,7 @@ const ROW = {
|
|
|
18493
18664
|
],
|
|
18494
18665
|
returns: ["NUMBER"],
|
|
18495
18666
|
compute: function (cellReference) {
|
|
18496
|
-
cellReference = cellReference || this.__originCellXC
|
|
18667
|
+
cellReference = cellReference || this.__originCellXC();
|
|
18497
18668
|
assert(() => !!cellReference, "In this context, the function [[FUNCTION_NAME]] needs to have a cell or range in parameter.");
|
|
18498
18669
|
const zone = toZone(cellReference);
|
|
18499
18670
|
return zone.top + 1;
|
|
@@ -19395,9 +19566,7 @@ const insertRow = {
|
|
|
19395
19566
|
const number = getRowsNumber(env);
|
|
19396
19567
|
return number === 1 ? _t("Insert row") : _t("Insert %s rows", number.toString());
|
|
19397
19568
|
},
|
|
19398
|
-
isVisible: (env) =>
|
|
19399
|
-
IS_ONLY_ONE_RANGE(env) &&
|
|
19400
|
-
env.model.getters.getActiveCols().size === 0,
|
|
19569
|
+
isVisible: (env) => CAN_INSERT_HEADER(env, "ROW"),
|
|
19401
19570
|
icon: "o-spreadsheet-Icon.INSERT_ROW",
|
|
19402
19571
|
};
|
|
19403
19572
|
const rowInsertRowBefore = {
|
|
@@ -19406,9 +19575,7 @@ const rowInsertRowBefore = {
|
|
|
19406
19575
|
return number === 1 ? _t("Insert row above") : _t("Insert %s rows above", number.toString());
|
|
19407
19576
|
},
|
|
19408
19577
|
execute: INSERT_ROWS_BEFORE_ACTION,
|
|
19409
|
-
isVisible: (env) =>
|
|
19410
|
-
IS_ONLY_ONE_RANGE(env) &&
|
|
19411
|
-
env.model.getters.getActiveCols().size === 0,
|
|
19578
|
+
isVisible: (env) => CAN_INSERT_HEADER(env, "ROW"),
|
|
19412
19579
|
icon: "o-spreadsheet-Icon.INSERT_ROW_BEFORE",
|
|
19413
19580
|
};
|
|
19414
19581
|
const topBarInsertRowsBefore = {
|
|
@@ -19439,9 +19606,7 @@ const rowInsertRowsAfter = {
|
|
|
19439
19606
|
const number = getRowsNumber(env);
|
|
19440
19607
|
return number === 1 ? _t("Insert row below") : _t("Insert %s rows below", number.toString());
|
|
19441
19608
|
},
|
|
19442
|
-
isVisible: (env) =>
|
|
19443
|
-
IS_ONLY_ONE_RANGE(env) &&
|
|
19444
|
-
env.model.getters.getActiveCols().size === 0,
|
|
19609
|
+
isVisible: (env) => CAN_INSERT_HEADER(env, "ROW"),
|
|
19445
19610
|
icon: "o-spreadsheet-Icon.INSERT_ROW_AFTER",
|
|
19446
19611
|
};
|
|
19447
19612
|
const topBarInsertRowsAfter = {
|
|
@@ -19459,9 +19624,7 @@ const insertCol = {
|
|
|
19459
19624
|
const number = getColumnsNumber(env);
|
|
19460
19625
|
return number === 1 ? _t("Insert column") : _t("Insert %s columns", number.toString());
|
|
19461
19626
|
},
|
|
19462
|
-
isVisible: (env) =>
|
|
19463
|
-
IS_ONLY_ONE_RANGE(env) &&
|
|
19464
|
-
env.model.getters.getActiveRows().size === 0,
|
|
19627
|
+
isVisible: (env) => CAN_INSERT_HEADER(env, "COL"),
|
|
19465
19628
|
icon: "o-spreadsheet-Icon.INSERT_COL",
|
|
19466
19629
|
};
|
|
19467
19630
|
const colInsertColsBefore = {
|
|
@@ -19472,9 +19635,7 @@ const colInsertColsBefore = {
|
|
|
19472
19635
|
: _t("Insert %s columns left", number.toString());
|
|
19473
19636
|
},
|
|
19474
19637
|
execute: INSERT_COLUMNS_BEFORE_ACTION,
|
|
19475
|
-
isVisible: (env) =>
|
|
19476
|
-
IS_ONLY_ONE_RANGE(env) &&
|
|
19477
|
-
env.model.getters.getActiveRows().size === 0,
|
|
19638
|
+
isVisible: (env) => CAN_INSERT_HEADER(env, "COL"),
|
|
19478
19639
|
icon: "o-spreadsheet-Icon.INSERT_COL_BEFORE",
|
|
19479
19640
|
};
|
|
19480
19641
|
const topBarInsertColsBefore = {
|
|
@@ -19507,9 +19668,7 @@ const colInsertColsAfter = {
|
|
|
19507
19668
|
: _t("Insert %s columns right", number.toString());
|
|
19508
19669
|
},
|
|
19509
19670
|
execute: INSERT_COLUMNS_AFTER_ACTION,
|
|
19510
|
-
isVisible: (env) =>
|
|
19511
|
-
IS_ONLY_ONE_RANGE(env) &&
|
|
19512
|
-
env.model.getters.getActiveRows().size === 0,
|
|
19671
|
+
isVisible: (env) => CAN_INSERT_HEADER(env, "COL"),
|
|
19513
19672
|
icon: "o-spreadsheet-Icon.INSERT_COL_AFTER",
|
|
19514
19673
|
};
|
|
19515
19674
|
const topBarInsertColsAfter = {
|
|
@@ -23850,38 +24009,72 @@ css /* scss */ `
|
|
|
23850
24009
|
}
|
|
23851
24010
|
.o-input-count {
|
|
23852
24011
|
width: fit-content;
|
|
23853
|
-
padding:
|
|
24012
|
+
padding: 4px 0 4px 4px;
|
|
23854
24013
|
}
|
|
23855
24014
|
}
|
|
23856
24015
|
}
|
|
23857
24016
|
`;
|
|
23858
24017
|
class FindAndReplacePanel extends Component {
|
|
23859
24018
|
static template = "o-spreadsheet-FindAndReplacePanel";
|
|
23860
|
-
|
|
24019
|
+
static components = { SelectionInput };
|
|
23861
24020
|
debounceTimeoutId;
|
|
23862
|
-
|
|
24021
|
+
initialShowFormulaState = false;
|
|
24022
|
+
dataRange = "";
|
|
23863
24023
|
searchInput = useRef("searchInput");
|
|
24024
|
+
replaceInput = useRef("replaceInput");
|
|
23864
24025
|
get hasSearchResult() {
|
|
23865
24026
|
return this.env.model.getters.getCurrentSelectedMatchIndex() !== null;
|
|
23866
24027
|
}
|
|
23867
24028
|
get pendingSearch() {
|
|
23868
24029
|
return this.debounceTimeoutId !== undefined;
|
|
23869
24030
|
}
|
|
24031
|
+
get searchOptions() {
|
|
24032
|
+
return this.env.model.getters.getSearchOptions();
|
|
24033
|
+
}
|
|
24034
|
+
get toSearch() {
|
|
24035
|
+
return this.searchInput.el?.value || "";
|
|
24036
|
+
}
|
|
24037
|
+
get toReplace() {
|
|
24038
|
+
return this.replaceInput.el?.value || "";
|
|
24039
|
+
}
|
|
24040
|
+
get allSheetsMatchesCount() {
|
|
24041
|
+
return _t("%s in all sheets", this.env.model.getters.getAllSheetMatchesCount());
|
|
24042
|
+
}
|
|
24043
|
+
get currentSheetMatchesCount() {
|
|
24044
|
+
return _t("%(matches)s in sheet %(sheetName)s", {
|
|
24045
|
+
matches: this.env.model.getters.getActiveSheetMatchesCount(),
|
|
24046
|
+
sheetName: this.env.model.getters.getSheetName(this.env.model.getters.getActiveSheetId()),
|
|
24047
|
+
});
|
|
24048
|
+
}
|
|
24049
|
+
get specificRangeMatchesCount() {
|
|
24050
|
+
const range = this.searchOptions.specificRange;
|
|
24051
|
+
if (!range) {
|
|
24052
|
+
return "";
|
|
24053
|
+
}
|
|
24054
|
+
const { _sheetId, _zone } = range;
|
|
24055
|
+
return _t("%(matches)s in range %(range)s of sheet %(sheetName)s", {
|
|
24056
|
+
matches: this.env.model.getters.getSpecificRangeMatchesCount().toString(),
|
|
24057
|
+
range: zoneToXc(_zone),
|
|
24058
|
+
sheetName: this.env.model.getters.getSheetName(_sheetId),
|
|
24059
|
+
});
|
|
24060
|
+
}
|
|
23870
24061
|
setup() {
|
|
23871
|
-
this.
|
|
24062
|
+
this.initialShowFormulaState = this.env.model.getters.shouldShowFormulas();
|
|
23872
24063
|
onMounted(() => this.searchInput.el?.focus());
|
|
23873
24064
|
onWillUnmount(() => {
|
|
23874
24065
|
clearTimeout(this.debounceTimeoutId);
|
|
23875
24066
|
this.env.model.dispatch("CLEAR_SEARCH");
|
|
23876
|
-
this.env.model.dispatch("SET_FORMULA_VISIBILITY", { show: this.
|
|
24067
|
+
this.env.model.dispatch("SET_FORMULA_VISIBILITY", { show: this.initialShowFormulaState });
|
|
23877
24068
|
});
|
|
23878
24069
|
useEffect(() => {
|
|
23879
|
-
|
|
23880
|
-
this.searchFormulas
|
|
24070
|
+
const showFormula = this.env.model.getters.shouldShowFormulas();
|
|
24071
|
+
this.updateSearch({ searchFormulas: showFormula });
|
|
23881
24072
|
}, () => [this.env.model.getters.shouldShowFormulas()]);
|
|
23882
24073
|
}
|
|
23883
|
-
|
|
23884
|
-
this.
|
|
24074
|
+
onFocusSearch() {
|
|
24075
|
+
this.updateDataRange();
|
|
24076
|
+
}
|
|
24077
|
+
onInput() {
|
|
23885
24078
|
this.debouncedUpdateSearch();
|
|
23886
24079
|
}
|
|
23887
24080
|
onKeydownSearch(ev) {
|
|
@@ -23898,11 +24091,36 @@ class FindAndReplacePanel extends Component {
|
|
|
23898
24091
|
this.replace();
|
|
23899
24092
|
}
|
|
23900
24093
|
}
|
|
23901
|
-
searchFormulas() {
|
|
24094
|
+
searchFormulas(ev) {
|
|
24095
|
+
const showFormula = ev.target.checked;
|
|
23902
24096
|
this.env.model.dispatch("SET_FORMULA_VISIBILITY", {
|
|
23903
|
-
show:
|
|
24097
|
+
show: showFormula,
|
|
23904
24098
|
});
|
|
23905
|
-
this.updateSearch();
|
|
24099
|
+
this.updateSearch({ searchFormulas: showFormula });
|
|
24100
|
+
}
|
|
24101
|
+
searchExactMatch(ev) {
|
|
24102
|
+
const exactMatch = ev.target.checked;
|
|
24103
|
+
this.updateSearch({ exactMatch });
|
|
24104
|
+
}
|
|
24105
|
+
searchMatchCase(ev) {
|
|
24106
|
+
const matchCase = ev.target.checked;
|
|
24107
|
+
this.updateSearch({ matchCase });
|
|
24108
|
+
}
|
|
24109
|
+
changeSearchScope(ev) {
|
|
24110
|
+
const searchScope = ev.target.value;
|
|
24111
|
+
this.updateSearch({ searchScope });
|
|
24112
|
+
}
|
|
24113
|
+
onSearchRangeChanged(ranges) {
|
|
24114
|
+
this.dataRange = ranges[0];
|
|
24115
|
+
}
|
|
24116
|
+
updateDataRange() {
|
|
24117
|
+
if (!this.dataRange) {
|
|
24118
|
+
return;
|
|
24119
|
+
}
|
|
24120
|
+
if (this.searchOptions.searchScope === "specificRange") {
|
|
24121
|
+
const specificRange = this.env.model.getters.getRangeFromSheetXC(this.env.model.getters.getActiveSheetId(), this.dataRange).rangeData;
|
|
24122
|
+
this.updateSearch({ specificRange });
|
|
24123
|
+
}
|
|
23906
24124
|
}
|
|
23907
24125
|
onSelectPreviousCell() {
|
|
23908
24126
|
this.env.model.dispatch("SELECT_SEARCH_PREVIOUS_MATCH");
|
|
@@ -23910,10 +24128,14 @@ class FindAndReplacePanel extends Component {
|
|
|
23910
24128
|
onSelectNextCell() {
|
|
23911
24129
|
this.env.model.dispatch("SELECT_SEARCH_NEXT_MATCH");
|
|
23912
24130
|
}
|
|
23913
|
-
updateSearch() {
|
|
24131
|
+
updateSearch(updateSearchOptions) {
|
|
24132
|
+
const searchOptions = {
|
|
24133
|
+
...this.env.model.getters.getSearchOptions(),
|
|
24134
|
+
...updateSearchOptions,
|
|
24135
|
+
};
|
|
23914
24136
|
this.env.model.dispatch("UPDATE_SEARCH", {
|
|
23915
|
-
toSearch: this.
|
|
23916
|
-
searchOptions
|
|
24137
|
+
toSearch: this.toSearch,
|
|
24138
|
+
searchOptions,
|
|
23917
24139
|
});
|
|
23918
24140
|
}
|
|
23919
24141
|
debouncedUpdateSearch() {
|
|
@@ -23925,28 +24147,14 @@ class FindAndReplacePanel extends Component {
|
|
|
23925
24147
|
}
|
|
23926
24148
|
replace() {
|
|
23927
24149
|
this.env.model.dispatch("REPLACE_SEARCH", {
|
|
23928
|
-
replaceWith: this.
|
|
24150
|
+
replaceWith: this.toReplace,
|
|
23929
24151
|
});
|
|
23930
24152
|
}
|
|
23931
24153
|
replaceAll() {
|
|
23932
24154
|
this.env.model.dispatch("REPLACE_ALL_SEARCH", {
|
|
23933
|
-
replaceWith: this.
|
|
24155
|
+
replaceWith: this.toReplace,
|
|
23934
24156
|
});
|
|
23935
24157
|
}
|
|
23936
|
-
// ---------------------------------------------------------------------------
|
|
23937
|
-
// Private
|
|
23938
|
-
// ---------------------------------------------------------------------------
|
|
23939
|
-
initialState() {
|
|
23940
|
-
return {
|
|
23941
|
-
toSearch: "",
|
|
23942
|
-
replaceWith: "",
|
|
23943
|
-
searchOptions: {
|
|
23944
|
-
matchCase: false,
|
|
23945
|
-
exactMatch: false,
|
|
23946
|
-
searchFormulas: false,
|
|
23947
|
-
},
|
|
23948
|
-
};
|
|
23949
|
-
}
|
|
23950
24158
|
}
|
|
23951
24159
|
FindAndReplacePanel.props = {
|
|
23952
24160
|
onCloseSidePanel: Function,
|
|
@@ -27092,7 +27300,7 @@ class GridComposer extends Component {
|
|
|
27092
27300
|
get cellReference() {
|
|
27093
27301
|
const { col, row, sheetId } = this.env.model.getters.getCurrentEditedCell();
|
|
27094
27302
|
const prefixSheet = sheetId !== this.env.model.getters.getActiveSheetId();
|
|
27095
|
-
return
|
|
27303
|
+
return getFullReference(prefixSheet ? this.env.model.getters.getSheetName(sheetId) : undefined, toXC(col, row));
|
|
27096
27304
|
}
|
|
27097
27305
|
get cellReferenceStyle() {
|
|
27098
27306
|
const { x: left, y: top } = this.rect;
|
|
@@ -28535,22 +28743,15 @@ css /* scss */ `
|
|
|
28535
28743
|
height: 10000px;
|
|
28536
28744
|
background-color: ${SELECTION_BORDER_COLOR};
|
|
28537
28745
|
}
|
|
28538
|
-
.o-unhide {
|
|
28539
|
-
width:
|
|
28540
|
-
|
|
28541
|
-
|
|
28542
|
-
overflow: hidden;
|
|
28543
|
-
border-radius: 2px;
|
|
28544
|
-
top: calc(${HEADER_HEIGHT}px / 2 - ${UNHIDE_ICON_EDGE_LENGTH}px / 2);
|
|
28746
|
+
.o-unhide-buttons {
|
|
28747
|
+
width: fit-content;
|
|
28748
|
+
gap: 5px;
|
|
28749
|
+
transform: translate(-50%, 0);
|
|
28545
28750
|
}
|
|
28546
28751
|
.o-unhide:hover {
|
|
28547
28752
|
z-index: ${ComponentsImportance.Grid + 1};
|
|
28548
28753
|
background-color: lightgrey;
|
|
28549
28754
|
}
|
|
28550
|
-
.o-unhide > svg {
|
|
28551
|
-
position: relative;
|
|
28552
|
-
top: calc(${UNHIDE_ICON_EDGE_LENGTH}px / 2 - ${ICON_EDGE_LENGTH}px / 2);
|
|
28553
|
-
}
|
|
28554
28755
|
}
|
|
28555
28756
|
`;
|
|
28556
28757
|
AbstractResizer.props = {
|
|
@@ -28660,8 +28861,8 @@ class ColResizer extends AbstractResizer {
|
|
|
28660
28861
|
dimension: "COL",
|
|
28661
28862
|
});
|
|
28662
28863
|
}
|
|
28663
|
-
|
|
28664
|
-
return this._getDimensionsInViewport(hiddenIndex).start;
|
|
28864
|
+
getUnhideButtonStyle(hiddenIndex) {
|
|
28865
|
+
return cssPropertiesToCss({ left: this._getDimensionsInViewport(hiddenIndex).start + "px" });
|
|
28665
28866
|
}
|
|
28666
28867
|
}
|
|
28667
28868
|
css /* scss */ `
|
|
@@ -28707,18 +28908,9 @@ css /* scss */ `
|
|
|
28707
28908
|
height: 1px;
|
|
28708
28909
|
background-color: ${SELECTION_BORDER_COLOR};
|
|
28709
28910
|
}
|
|
28710
|
-
.o-unhide {
|
|
28711
|
-
|
|
28712
|
-
|
|
28713
|
-
position: absolute;
|
|
28714
|
-
overflow: hidden;
|
|
28715
|
-
border-radius: 2px;
|
|
28716
|
-
left: calc(${HEADER_WIDTH}px - ${UNHIDE_ICON_EDGE_LENGTH}px - 2px);
|
|
28717
|
-
}
|
|
28718
|
-
.o-unhide > svg {
|
|
28719
|
-
position: relative;
|
|
28720
|
-
left: calc(${UNHIDE_ICON_EDGE_LENGTH}px / 2 - ${ICON_EDGE_LENGTH}px / 2);
|
|
28721
|
-
top: calc(${UNHIDE_ICON_EDGE_LENGTH}px / 2 - ${ICON_EDGE_LENGTH}px / 2);
|
|
28911
|
+
.o-unhide-buttons {
|
|
28912
|
+
height: fit-content;
|
|
28913
|
+
transform: translate(0, -50%);
|
|
28722
28914
|
}
|
|
28723
28915
|
.o-unhide:hover {
|
|
28724
28916
|
z-index: ${ComponentsImportance.Grid + 1};
|
|
@@ -28833,8 +29025,8 @@ class RowResizer extends AbstractResizer {
|
|
|
28833
29025
|
elements: hiddenElements,
|
|
28834
29026
|
});
|
|
28835
29027
|
}
|
|
28836
|
-
|
|
28837
|
-
return this._getDimensionsInViewport(hiddenIndex).start;
|
|
29028
|
+
getUnhideButtonStyle(hiddenIndex) {
|
|
29029
|
+
return cssPropertiesToCss({ top: this._getDimensionsInViewport(hiddenIndex).start + "px" });
|
|
28838
29030
|
}
|
|
28839
29031
|
}
|
|
28840
29032
|
css /* scss */ `
|
|
@@ -29341,7 +29533,6 @@ class Grid extends Component {
|
|
|
29341
29533
|
onMounted(() => this.focus());
|
|
29342
29534
|
this.props.exposeFocus(() => this.focus());
|
|
29343
29535
|
useGridDrawing("canvas", this.env.model, () => this.env.model.getters.getSheetViewDimensionWithHeaders());
|
|
29344
|
-
useEffect(() => this.focus(), () => [this.env.model.getters.getActiveSheetId()]);
|
|
29345
29536
|
this.onMouseWheel = useWheelHandler((deltaX, deltaY) => {
|
|
29346
29537
|
this.moveCanvas(deltaX, deltaY);
|
|
29347
29538
|
this.hoveredCell.col = undefined;
|
|
@@ -29778,6 +29969,7 @@ class Grid extends Component {
|
|
|
29778
29969
|
const content = clipboardData.getData(ClipboardMIMEType.PlainText);
|
|
29779
29970
|
const target = this.env.model.getters.getSelectedZones();
|
|
29780
29971
|
const clipboardString = this.env.model.getters.getClipboardTextContent();
|
|
29972
|
+
const isCutOperation = this.env.model.getters.isCutOperation();
|
|
29781
29973
|
if (clipboardString === content) {
|
|
29782
29974
|
// the paste actually comes from o-spreadsheet itself
|
|
29783
29975
|
interactivePaste(this.env, target);
|
|
@@ -29785,7 +29977,7 @@ class Grid extends Component {
|
|
|
29785
29977
|
else {
|
|
29786
29978
|
interactivePasteFromOS(this.env, target, content);
|
|
29787
29979
|
}
|
|
29788
|
-
if (
|
|
29980
|
+
if (isCutOperation) {
|
|
29789
29981
|
await this.env.clipboard.write({ [ClipboardMIMEType.PlainText]: "" });
|
|
29790
29982
|
}
|
|
29791
29983
|
}
|
|
@@ -31398,12 +31590,6 @@ function convertChartData(chartData) {
|
|
|
31398
31590
|
}
|
|
31399
31591
|
function convertExcelRangeToSheetXC(range, dataSetsHaveTitle) {
|
|
31400
31592
|
let { sheetName, xc } = splitReference(range);
|
|
31401
|
-
if (sheetName) {
|
|
31402
|
-
sheetName = getCanonicalSheetName(sheetName) + "!";
|
|
31403
|
-
}
|
|
31404
|
-
else {
|
|
31405
|
-
sheetName = "";
|
|
31406
|
-
}
|
|
31407
31593
|
let zone = toUnboundedZone(xc);
|
|
31408
31594
|
if (dataSetsHaveTitle && zone.bottom !== undefined && zone.right !== undefined) {
|
|
31409
31595
|
const height = zone.bottom - zone.top + 1;
|
|
@@ -31416,7 +31602,7 @@ function convertExcelRangeToSheetXC(range, dataSetsHaveTitle) {
|
|
|
31416
31602
|
}
|
|
31417
31603
|
}
|
|
31418
31604
|
const dataXC = zoneToXc(zone);
|
|
31419
|
-
return sheetName
|
|
31605
|
+
return getFullReference(sheetName, dataXC);
|
|
31420
31606
|
}
|
|
31421
31607
|
|
|
31422
31608
|
/**
|
|
@@ -34079,6 +34265,14 @@ class BordersPlugin extends CorePlugin {
|
|
|
34079
34265
|
// ---------------------------------------------------------------------------
|
|
34080
34266
|
// Command Handling
|
|
34081
34267
|
// ---------------------------------------------------------------------------
|
|
34268
|
+
allowDispatch(cmd) {
|
|
34269
|
+
switch (cmd.type) {
|
|
34270
|
+
case "SET_BORDER":
|
|
34271
|
+
return this.checkBordersUnchanged(cmd);
|
|
34272
|
+
default:
|
|
34273
|
+
return "Success" /* CommandResult.Success */;
|
|
34274
|
+
}
|
|
34275
|
+
}
|
|
34082
34276
|
handle(cmd) {
|
|
34083
34277
|
switch (cmd.type) {
|
|
34084
34278
|
case "ADD_MERGE":
|
|
@@ -34498,6 +34692,14 @@ class BordersPlugin extends CorePlugin {
|
|
|
34498
34692
|
this.setBorders(sheetId, [{ ...zone, left: right }], "right", bordersTopLeft.right);
|
|
34499
34693
|
}
|
|
34500
34694
|
}
|
|
34695
|
+
checkBordersUnchanged(cmd) {
|
|
34696
|
+
const currentBorder = this.getCellBorder(cmd);
|
|
34697
|
+
const areAllNewBordersUndefined = !cmd.border?.bottom && !cmd.border?.left && !cmd.border?.right && !cmd.border?.top;
|
|
34698
|
+
if ((!currentBorder && areAllNewBordersUndefined) || deepEquals(currentBorder, cmd.border)) {
|
|
34699
|
+
return "NoChanges" /* CommandResult.NoChanges */;
|
|
34700
|
+
}
|
|
34701
|
+
return "Success" /* CommandResult.Success */;
|
|
34702
|
+
}
|
|
34501
34703
|
// ---------------------------------------------------------------------------
|
|
34502
34704
|
// Import/Export
|
|
34503
34705
|
// ---------------------------------------------------------------------------
|
|
@@ -34966,6 +35168,9 @@ const functionCache = {};
|
|
|
34966
35168
|
// -----------------------------------------------------------------------------
|
|
34967
35169
|
function compile(formula) {
|
|
34968
35170
|
const tokens = rangeTokenize(formula);
|
|
35171
|
+
return compileTokens(tokens);
|
|
35172
|
+
}
|
|
35173
|
+
function compileTokens(tokens) {
|
|
34969
35174
|
const { dependencies, constantValues } = formulaArguments(tokens);
|
|
34970
35175
|
const cacheKey = compilationCacheKey(tokens, dependencies, constantValues);
|
|
34971
35176
|
if (!functionCache[cacheKey]) {
|
|
@@ -35321,7 +35526,6 @@ class CellPlugin extends CorePlugin {
|
|
|
35321
35526
|
static getters = [
|
|
35322
35527
|
"zoneToXC",
|
|
35323
35528
|
"getCells",
|
|
35324
|
-
"getFormulaCellContent",
|
|
35325
35529
|
"getTranslatedCellFormula",
|
|
35326
35530
|
"getCellStyle",
|
|
35327
35531
|
"getCellById",
|
|
@@ -35332,11 +35536,11 @@ class CellPlugin extends CorePlugin {
|
|
|
35332
35536
|
for (const sheet of Object.keys(this.cells)) {
|
|
35333
35537
|
for (const cell of Object.values(this.cells[sheet] || {})) {
|
|
35334
35538
|
if (cell.isFormula) {
|
|
35335
|
-
for (const range of cell.dependencies) {
|
|
35539
|
+
for (const range of cell.compiledFormula.dependencies) {
|
|
35336
35540
|
if (!sheetId || range.sheetId === sheetId) {
|
|
35337
35541
|
const change = applyChange(range);
|
|
35338
35542
|
if (change.changeType !== "NONE") {
|
|
35339
|
-
this.history.update("cells", sheet, cell.id, "dependencies", cell.dependencies.indexOf(range), change.range);
|
|
35543
|
+
this.history.update("cells", sheet, cell.id, "compiledFormula", "dependencies", cell.compiledFormula.dependencies.indexOf(range), change.range);
|
|
35340
35544
|
}
|
|
35341
35545
|
}
|
|
35342
35546
|
}
|
|
@@ -35350,8 +35554,9 @@ class CellPlugin extends CorePlugin {
|
|
|
35350
35554
|
allowDispatch(cmd) {
|
|
35351
35555
|
switch (cmd.type) {
|
|
35352
35556
|
case "UPDATE_CELL":
|
|
35557
|
+
return this.checkCellOutOfSheet(cmd);
|
|
35353
35558
|
case "CLEAR_CELL":
|
|
35354
|
-
return this.
|
|
35559
|
+
return this.checkValidations(cmd, this.chainValidations(this.checkCellOutOfSheet, this.checkUselessClearCell));
|
|
35355
35560
|
default:
|
|
35356
35561
|
return "Success" /* CommandResult.Success */;
|
|
35357
35562
|
}
|
|
@@ -35520,24 +35725,18 @@ class CellPlugin extends CorePlugin {
|
|
|
35520
35725
|
*/
|
|
35521
35726
|
getCellById(cellId) {
|
|
35522
35727
|
// this must be as fast as possible
|
|
35523
|
-
|
|
35524
|
-
|
|
35525
|
-
|
|
35526
|
-
if (cell) {
|
|
35527
|
-
return cell;
|
|
35528
|
-
}
|
|
35529
|
-
}
|
|
35530
|
-
return undefined;
|
|
35728
|
+
const position = this.getters.getCellPosition(cellId);
|
|
35729
|
+
const sheet = this.cells[position.sheetId];
|
|
35730
|
+
return sheet[cellId];
|
|
35531
35731
|
}
|
|
35532
35732
|
/*
|
|
35533
35733
|
* Reconstructs the original formula string based on a normalized form and its dependencies
|
|
35534
35734
|
*/
|
|
35535
|
-
getFormulaCellContent(sheetId,
|
|
35536
|
-
const ranges = dependencies || cell.dependencies;
|
|
35735
|
+
getFormulaCellContent(sheetId, compiledFormula, dependencies) {
|
|
35537
35736
|
let rangeIndex = 0;
|
|
35538
|
-
return concat(
|
|
35737
|
+
return concat(compiledFormula.tokens.map((token) => {
|
|
35539
35738
|
if (token.type === "REFERENCE") {
|
|
35540
|
-
const range =
|
|
35739
|
+
const range = dependencies[rangeIndex++];
|
|
35541
35740
|
return this.getters.getRangeString(range, sheetId);
|
|
35542
35741
|
}
|
|
35543
35742
|
return token.value;
|
|
@@ -35546,12 +35745,9 @@ class CellPlugin extends CorePlugin {
|
|
|
35546
35745
|
/*
|
|
35547
35746
|
* Constructs a formula string based on an initial formula and a translation vector
|
|
35548
35747
|
*/
|
|
35549
|
-
getTranslatedCellFormula(sheetId, offsetX, offsetY, compiledFormula
|
|
35550
|
-
const adaptedDependencies = this.getters.createAdaptedRanges(dependencies, offsetX, offsetY, sheetId);
|
|
35551
|
-
return this.getFormulaCellContent(sheetId,
|
|
35552
|
-
compiledFormula,
|
|
35553
|
-
dependencies: adaptedDependencies,
|
|
35554
|
-
});
|
|
35748
|
+
getTranslatedCellFormula(sheetId, offsetX, offsetY, compiledFormula) {
|
|
35749
|
+
const adaptedDependencies = this.getters.createAdaptedRanges(compiledFormula.dependencies, offsetX, offsetY, sheetId);
|
|
35750
|
+
return this.getFormulaCellContent(sheetId, compiledFormula, adaptedDependencies);
|
|
35555
35751
|
}
|
|
35556
35752
|
getCellStyle(position) {
|
|
35557
35753
|
return this.getters.getCell(position)?.style || {};
|
|
@@ -35731,8 +35927,10 @@ class CellPlugin extends CorePlugin {
|
|
|
35731
35927
|
style,
|
|
35732
35928
|
format,
|
|
35733
35929
|
isFormula: true,
|
|
35734
|
-
compiledFormula
|
|
35735
|
-
|
|
35930
|
+
compiledFormula: {
|
|
35931
|
+
...compiledFormula,
|
|
35932
|
+
dependencies: [],
|
|
35933
|
+
},
|
|
35736
35934
|
};
|
|
35737
35935
|
}
|
|
35738
35936
|
/**
|
|
@@ -35741,7 +35939,7 @@ class CellPlugin extends CorePlugin {
|
|
|
35741
35939
|
*/
|
|
35742
35940
|
createFormulaCellWithDependencies(id, compiledFormula, format, style, sheetId) {
|
|
35743
35941
|
const dependencies = compiledFormula.dependencies.map((xc) => this.getters.getRangeFromSheetXC(sheetId, xc));
|
|
35744
|
-
return new FormulaCellWithDependencies(id, compiledFormula, format, style, dependencies, sheetId, this.
|
|
35942
|
+
return new FormulaCellWithDependencies(id, compiledFormula, format, style, dependencies, sheetId, this.getters.getRangeString.bind(this));
|
|
35745
35943
|
}
|
|
35746
35944
|
createErrorFormula(id, content, format, style, error) {
|
|
35747
35945
|
return {
|
|
@@ -35751,46 +35949,72 @@ class CellPlugin extends CorePlugin {
|
|
|
35751
35949
|
format,
|
|
35752
35950
|
isFormula: true,
|
|
35753
35951
|
compiledFormula: {
|
|
35754
|
-
dependencies: [],
|
|
35755
35952
|
tokens: tokenize(content),
|
|
35953
|
+
dependencies: [],
|
|
35756
35954
|
execute: function () {
|
|
35757
35955
|
throw error;
|
|
35758
35956
|
},
|
|
35759
35957
|
},
|
|
35760
|
-
dependencies: [],
|
|
35761
35958
|
};
|
|
35762
35959
|
}
|
|
35763
|
-
checkCellOutOfSheet(
|
|
35960
|
+
checkCellOutOfSheet(cmd) {
|
|
35961
|
+
const { sheetId, col, row } = cmd;
|
|
35764
35962
|
const sheet = this.getters.tryGetSheet(sheetId);
|
|
35765
35963
|
if (!sheet)
|
|
35766
35964
|
return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
|
|
35767
35965
|
const sheetZone = this.getters.getSheetZone(sheetId);
|
|
35768
35966
|
return isInside(col, row, sheetZone) ? "Success" /* CommandResult.Success */ : "TargetOutOfSheet" /* CommandResult.TargetOutOfSheet */;
|
|
35769
35967
|
}
|
|
35968
|
+
checkUselessClearCell(cmd) {
|
|
35969
|
+
const cell = this.getters.getCell(cmd);
|
|
35970
|
+
if (!cell)
|
|
35971
|
+
return "NoChanges" /* CommandResult.NoChanges */;
|
|
35972
|
+
if (!cell.content && !cell.style && !cell.format) {
|
|
35973
|
+
return "NoChanges" /* CommandResult.NoChanges */;
|
|
35974
|
+
}
|
|
35975
|
+
return "Success" /* CommandResult.Success */;
|
|
35976
|
+
}
|
|
35770
35977
|
}
|
|
35771
35978
|
class FormulaCellWithDependencies {
|
|
35772
35979
|
id;
|
|
35773
|
-
compiledFormula;
|
|
35774
35980
|
format;
|
|
35775
35981
|
style;
|
|
35776
|
-
dependencies;
|
|
35777
35982
|
sheetId;
|
|
35778
|
-
|
|
35983
|
+
getRangeString;
|
|
35779
35984
|
isFormula = true;
|
|
35780
|
-
|
|
35985
|
+
compiledFormula;
|
|
35986
|
+
constructor(id, compiledFormula, format, style, dependencies, sheetId, getRangeString) {
|
|
35781
35987
|
this.id = id;
|
|
35782
|
-
this.compiledFormula = compiledFormula;
|
|
35783
35988
|
this.format = format;
|
|
35784
35989
|
this.style = style;
|
|
35785
|
-
this.dependencies = dependencies;
|
|
35786
35990
|
this.sheetId = sheetId;
|
|
35787
|
-
this.
|
|
35991
|
+
this.getRangeString = getRangeString;
|
|
35992
|
+
let rangeIndex = 0;
|
|
35993
|
+
const tokens = compiledFormula.tokens.map((token) => {
|
|
35994
|
+
if (token.type === "REFERENCE") {
|
|
35995
|
+
const index = rangeIndex++;
|
|
35996
|
+
return new RangeReferenceToken(() => this.getRangeString(dependencies[index], this.sheetId));
|
|
35997
|
+
}
|
|
35998
|
+
return token;
|
|
35999
|
+
});
|
|
36000
|
+
this.compiledFormula = {
|
|
36001
|
+
...compiledFormula,
|
|
36002
|
+
dependencies,
|
|
36003
|
+
tokens,
|
|
36004
|
+
};
|
|
35788
36005
|
}
|
|
35789
36006
|
get content() {
|
|
35790
|
-
return this.
|
|
35791
|
-
|
|
35792
|
-
|
|
35793
|
-
|
|
36007
|
+
return concat(this.compiledFormula.tokens.map((token) => token.value));
|
|
36008
|
+
}
|
|
36009
|
+
}
|
|
36010
|
+
class RangeReferenceToken {
|
|
36011
|
+
getValue;
|
|
36012
|
+
type = "REFERENCE";
|
|
36013
|
+
constructor(getValue) {
|
|
36014
|
+
this.getValue = getValue;
|
|
36015
|
+
}
|
|
36016
|
+
get value() {
|
|
36017
|
+
return this.getValue();
|
|
35794
36018
|
}
|
|
35795
36019
|
}
|
|
35796
36020
|
|
|
@@ -36439,6 +36663,9 @@ class DataValidationPlugin extends CorePlugin {
|
|
|
36439
36663
|
return this.rules[sheetId].find((rule) => rule.id === id);
|
|
36440
36664
|
}
|
|
36441
36665
|
getValidationRuleForCell({ sheetId, col, row }) {
|
|
36666
|
+
if (!this.rules[sheetId]) {
|
|
36667
|
+
return undefined;
|
|
36668
|
+
}
|
|
36442
36669
|
for (const rule of this.rules[sheetId]) {
|
|
36443
36670
|
for (const range of rule.ranges) {
|
|
36444
36671
|
if (isInside(col, row, range.zone)) {
|
|
@@ -36935,6 +37162,13 @@ class FiltersPlugin extends CorePlugin {
|
|
|
36935
37162
|
}
|
|
36936
37163
|
onDeleteColumnsRows(cmd) {
|
|
36937
37164
|
for (const table of this.getFilterTables(cmd.sheetId)) {
|
|
37165
|
+
// Remove the filter tables whose data filter headers are in the removed rows.
|
|
37166
|
+
if (cmd.dimension === "ROW" && cmd.elements.includes(table.zone.top)) {
|
|
37167
|
+
const tables = { ...this.tables[cmd.sheetId] };
|
|
37168
|
+
delete tables[table.id];
|
|
37169
|
+
this.history.update("tables", cmd.sheetId, tables);
|
|
37170
|
+
continue;
|
|
37171
|
+
}
|
|
36938
37172
|
const zone = reduceZoneOnDeletion(table.zone, cmd.dimension === "COL" ? "left" : "top", cmd.elements);
|
|
36939
37173
|
if (!zone) {
|
|
36940
37174
|
const tables = { ...this.tables[cmd.sheetId] };
|
|
@@ -37604,7 +37838,7 @@ class MergePlugin extends CorePlugin {
|
|
|
37604
37838
|
const rangeString = this.getters.getRangeString(expandedRange, forSheetId);
|
|
37605
37839
|
if (this.isSingleCellOrMerge(rangeImpl.sheetId, rangeImpl.zone)) {
|
|
37606
37840
|
const { sheetName, xc } = splitReference(rangeString);
|
|
37607
|
-
return
|
|
37841
|
+
return getFullReference(sheetName, xc.split(":")[0]);
|
|
37608
37842
|
}
|
|
37609
37843
|
return rangeString;
|
|
37610
37844
|
}
|
|
@@ -39029,10 +39263,13 @@ class SheetPlugin extends CorePlugin {
|
|
|
39029
39263
|
// begin with the end.
|
|
39030
39264
|
rows.sort((a, b) => b - a);
|
|
39031
39265
|
for (let group of groupConsecutive(rows)) {
|
|
39266
|
+
// indexes are sorted in the descending order
|
|
39267
|
+
const from = group[group.length - 1];
|
|
39268
|
+
const to = group[0];
|
|
39032
39269
|
// Move the cells.
|
|
39033
|
-
this.moveCellOnRowsDeletion(sheet,
|
|
39034
|
-
// Effectively delete the
|
|
39035
|
-
|
|
39270
|
+
this.moveCellOnRowsDeletion(sheet, from, to);
|
|
39271
|
+
// Effectively delete the rows
|
|
39272
|
+
this.updateRowsStructureOnDeletion(sheet, from, to);
|
|
39036
39273
|
}
|
|
39037
39274
|
const count = rows.filter((row) => row < sheet.panes.ySplit).length;
|
|
39038
39275
|
if (count) {
|
|
@@ -39054,8 +39291,6 @@ class SheetPlugin extends CorePlugin {
|
|
|
39054
39291
|
this.addEmptyRows(sheet, quantity);
|
|
39055
39292
|
// Move the cells.
|
|
39056
39293
|
this.moveCellsOnAddition(sheet, index, quantity, "rows");
|
|
39057
|
-
// Recompute the left-right/top-bottom.
|
|
39058
|
-
this.updateRowsStructureOnAddition(sheet, row, quantity);
|
|
39059
39294
|
if (index < sheet.panes.ySplit) {
|
|
39060
39295
|
this.setPaneDivisions(sheet.id, sheet.panes.ySplit + quantity, "ROW");
|
|
39061
39296
|
}
|
|
@@ -39156,35 +39391,20 @@ class SheetPlugin extends CorePlugin {
|
|
|
39156
39391
|
}
|
|
39157
39392
|
}
|
|
39158
39393
|
}
|
|
39159
|
-
updateRowsStructureOnDeletion(
|
|
39394
|
+
updateRowsStructureOnDeletion(sheet, deleteFromRow, deleteToRow) {
|
|
39160
39395
|
const rows = [];
|
|
39161
|
-
const cellsQueue = sheet.rows.map((row) => row.cells);
|
|
39396
|
+
const cellsQueue = sheet.rows.map((row) => row.cells).reverse();
|
|
39162
39397
|
for (let i in sheet.rows) {
|
|
39163
|
-
|
|
39398
|
+
const row = Number(i);
|
|
39399
|
+
if (row >= deleteFromRow && row <= deleteToRow) {
|
|
39164
39400
|
continue;
|
|
39165
39401
|
}
|
|
39166
39402
|
rows.push({
|
|
39167
|
-
cells: cellsQueue.
|
|
39403
|
+
cells: cellsQueue.pop(),
|
|
39168
39404
|
});
|
|
39169
39405
|
}
|
|
39170
39406
|
this.history.update("sheets", sheet.id, "rows", rows);
|
|
39171
39407
|
}
|
|
39172
|
-
/**
|
|
39173
|
-
* Update the rows of the sheet after an addition:
|
|
39174
|
-
* - Rename the rows
|
|
39175
|
-
*
|
|
39176
|
-
* @param sheet Sheet on which the deletion occurs
|
|
39177
|
-
* @param addedRow Index of the added row
|
|
39178
|
-
* @param rowsToAdd Number of the rows to add
|
|
39179
|
-
*/
|
|
39180
|
-
updateRowsStructureOnAddition(sheet, addedRow, rowsToAdd) {
|
|
39181
|
-
const rows = [];
|
|
39182
|
-
const cellsQueue = sheet.rows.map((row) => row.cells);
|
|
39183
|
-
sheet.rows.forEach(() => rows.push({
|
|
39184
|
-
cells: cellsQueue.shift(),
|
|
39185
|
-
}));
|
|
39186
|
-
this.history.update("sheets", sheet.id, "rows", rows);
|
|
39187
|
-
}
|
|
39188
39408
|
/**
|
|
39189
39409
|
* Add empty rows at the end of the rows
|
|
39190
39410
|
*
|
|
@@ -39711,6 +39931,7 @@ class CompilationParametersBuilder {
|
|
|
39711
39931
|
getters;
|
|
39712
39932
|
computeCell;
|
|
39713
39933
|
evalContext;
|
|
39934
|
+
rangeCache = {};
|
|
39714
39935
|
constructor(context, getters, computeCell) {
|
|
39715
39936
|
this.getters = getters;
|
|
39716
39937
|
this.computeCell = computeCell;
|
|
@@ -39733,7 +39954,8 @@ class CompilationParametersBuilder {
|
|
|
39733
39954
|
refFn(range, isMeta, functionName, paramNumber) {
|
|
39734
39955
|
if (isMeta) {
|
|
39735
39956
|
// Use zoneToXc of zone instead of getRangeString to avoid sending unbounded ranges
|
|
39736
|
-
|
|
39957
|
+
const sheetName = this.getters.getSheetName(range.sheetId);
|
|
39958
|
+
return { value: getFullReference(sheetName, zoneToXc(range.zone)) };
|
|
39737
39959
|
}
|
|
39738
39960
|
if (!isZoneValid(range.zone)) {
|
|
39739
39961
|
throw new InvalidReferenceError();
|
|
@@ -39796,17 +40018,24 @@ class CompilationParametersBuilder {
|
|
|
39796
40018
|
if (!_zone) {
|
|
39797
40019
|
return [[]];
|
|
39798
40020
|
}
|
|
40021
|
+
const { top, left, bottom, right } = zone;
|
|
40022
|
+
const cacheKey = `${sheetId}-${top}-${left}-${bottom}-${right}`;
|
|
40023
|
+
if (cacheKey in this.rangeCache) {
|
|
40024
|
+
return this.rangeCache[cacheKey];
|
|
40025
|
+
}
|
|
39799
40026
|
const height = _zone.bottom - _zone.top + 1;
|
|
39800
40027
|
const width = _zone.right - _zone.left + 1;
|
|
39801
|
-
const matrix = Array
|
|
40028
|
+
const matrix = new Array(width);
|
|
39802
40029
|
// Performance issue: nested loop is faster than a map here
|
|
39803
40030
|
for (let col = _zone.left; col <= _zone.right; col++) {
|
|
40031
|
+
const colIndex = col - _zone.left;
|
|
40032
|
+
matrix[colIndex] = new Array(height);
|
|
39804
40033
|
for (let row = _zone.top; row <= _zone.bottom; row++) {
|
|
39805
|
-
const colIndex = col - _zone.left;
|
|
39806
40034
|
const rowIndex = row - _zone.top;
|
|
39807
40035
|
matrix[colIndex][rowIndex] = this.readCell({ sheetId, col, row });
|
|
39808
40036
|
}
|
|
39809
40037
|
}
|
|
40038
|
+
this.rangeCache[cacheKey] = matrix;
|
|
39810
40039
|
return matrix;
|
|
39811
40040
|
}
|
|
39812
40041
|
}
|
|
@@ -39983,6 +40212,13 @@ class Evaluator {
|
|
|
39983
40212
|
return (this.evaluatedCells.get(this.encodePosition(position)) ||
|
|
39984
40213
|
createEvaluatedCell("", { locale: this.getters.getLocale() }));
|
|
39985
40214
|
}
|
|
40215
|
+
getSpreadPositionsOf(position) {
|
|
40216
|
+
const positionId = this.encodePosition(position);
|
|
40217
|
+
if (!this.spreadingRelations.isArrayFormula(positionId)) {
|
|
40218
|
+
return [];
|
|
40219
|
+
}
|
|
40220
|
+
return Array.from(this.spreadingRelations.getArrayResultPositionIds(positionId)).map(this.decodePosition.bind(this));
|
|
40221
|
+
}
|
|
39986
40222
|
getArrayFormulaSpreadingOn(position) {
|
|
39987
40223
|
const positionId = this.encodePosition(position);
|
|
39988
40224
|
const formulaPosition = this.getArrayFormulaSpreadingOnId(positionId);
|
|
@@ -40005,6 +40241,7 @@ class Evaluator {
|
|
|
40005
40241
|
this.formulaDependencies().addDependencies(positionId, dependencies);
|
|
40006
40242
|
}
|
|
40007
40243
|
updateCompilationParameters() {
|
|
40244
|
+
// rebuild the compilation parameters (with a clean cache)
|
|
40008
40245
|
this.compilationParams = buildCompilationParameters(this.context, this.getters, this.computeAndSave.bind(this));
|
|
40009
40246
|
}
|
|
40010
40247
|
evaluateCells(positions) {
|
|
@@ -40048,6 +40285,16 @@ class Evaluator {
|
|
|
40048
40285
|
this.evaluatedCells = new Map();
|
|
40049
40286
|
this.evaluate(this.getAllCells());
|
|
40050
40287
|
}
|
|
40288
|
+
evaluateFormula(sheetId, formulaString) {
|
|
40289
|
+
const compiledFormula = compile(formulaString);
|
|
40290
|
+
const ranges = compiledFormula.dependencies.map((xc) => this.getters.getRangeFromSheetXC(sheetId, xc));
|
|
40291
|
+
this.updateCompilationParameters();
|
|
40292
|
+
const result = updateEvalContextAndExecute({ ...compiledFormula, dependencies: ranges }, this.compilationParams, sheetId);
|
|
40293
|
+
if (isMatrix(result)) {
|
|
40294
|
+
return matrixMap(result, (cell) => cell.value);
|
|
40295
|
+
}
|
|
40296
|
+
return result.value;
|
|
40297
|
+
}
|
|
40051
40298
|
getAllCells() {
|
|
40052
40299
|
const positionIds = new JetSet();
|
|
40053
40300
|
for (const sheetId of this.getters.getSheetIds()) {
|
|
@@ -40074,6 +40321,7 @@ class Evaluator {
|
|
|
40074
40321
|
this.nextPositionsToUpdate = cells;
|
|
40075
40322
|
let currentIteration = 0;
|
|
40076
40323
|
while (this.nextPositionsToUpdate.size && currentIteration++ < MAX_ITERATION) {
|
|
40324
|
+
this.updateCompilationParameters();
|
|
40077
40325
|
const positionIds = Array.from(this.nextPositionsToUpdate);
|
|
40078
40326
|
this.nextPositionsToUpdate.clear();
|
|
40079
40327
|
for (let i = 0; i < positionIds.length; ++i) {
|
|
@@ -40097,7 +40345,8 @@ class Evaluator {
|
|
|
40097
40345
|
if (!this.blockedArrayFormulas.has(positionId)) {
|
|
40098
40346
|
this.invalidateSpreading(positionId);
|
|
40099
40347
|
}
|
|
40100
|
-
const
|
|
40348
|
+
const cellPosition = this.decodePosition(positionId);
|
|
40349
|
+
const cell = this.getters.getCell(cellPosition);
|
|
40101
40350
|
if (cell === undefined) {
|
|
40102
40351
|
return createEvaluatedCell("", { locale: this.getters.getLocale() });
|
|
40103
40352
|
}
|
|
@@ -40108,7 +40357,7 @@ class Evaluator {
|
|
|
40108
40357
|
}
|
|
40109
40358
|
this.cellsBeingComputed.add(cellId);
|
|
40110
40359
|
return cell.isFormula
|
|
40111
|
-
? this.computeFormulaCell(cell)
|
|
40360
|
+
? this.computeFormulaCell(cellPosition.sheetId, cell)
|
|
40112
40361
|
: evaluateLiteral(cell.content, { format: cell.format, locale: this.getters.getLocale() });
|
|
40113
40362
|
}
|
|
40114
40363
|
catch (e) {
|
|
@@ -40134,14 +40383,9 @@ class Evaluator {
|
|
|
40134
40383
|
e.message = e.message.replace("[[FUNCTION_NAME]]", __lastFnCalled);
|
|
40135
40384
|
return errorCell(e);
|
|
40136
40385
|
}
|
|
40137
|
-
computeFormulaCell(cellData) {
|
|
40386
|
+
computeFormulaCell(sheetId, cellData) {
|
|
40138
40387
|
const cellId = cellData.id;
|
|
40139
|
-
this.compilationParams
|
|
40140
|
-
// compute the value lazily for performance reasons
|
|
40141
|
-
const position = this.compilationParams[2].getters.getCellPosition(cellId);
|
|
40142
|
-
return toXC(position.col, position.row);
|
|
40143
|
-
};
|
|
40144
|
-
const formulaReturn = cellData.compiledFormula.execute(cellData.dependencies, ...this.compilationParams);
|
|
40388
|
+
const formulaReturn = updateEvalContextAndExecute(cellData.compiledFormula, this.compilationParams, sheetId, cellId);
|
|
40145
40389
|
if (!isMatrix(formulaReturn)) {
|
|
40146
40390
|
return createEvaluatedCell(formulaReturn.value, {
|
|
40147
40391
|
format: cellData.format || formulaReturn.format,
|
|
@@ -40241,7 +40485,7 @@ class Evaluator {
|
|
|
40241
40485
|
return [];
|
|
40242
40486
|
}
|
|
40243
40487
|
const dependencies = [];
|
|
40244
|
-
for (const range of cell.dependencies) {
|
|
40488
|
+
for (const range of cell.compiledFormula.dependencies) {
|
|
40245
40489
|
if (range.invalidSheetName || range.invalidXc) {
|
|
40246
40490
|
continue;
|
|
40247
40491
|
}
|
|
@@ -40343,6 +40587,18 @@ class PositionBitsEncoder {
|
|
|
40343
40587
|
return sheetId;
|
|
40344
40588
|
}
|
|
40345
40589
|
}
|
|
40590
|
+
function updateEvalContextAndExecute(compiledFormula, compilationParams, sheetId, cellId) {
|
|
40591
|
+
compilationParams[2].__originCellXC = lazy(() => {
|
|
40592
|
+
if (!cellId) {
|
|
40593
|
+
return undefined;
|
|
40594
|
+
}
|
|
40595
|
+
// compute the value lazily for performance reasons
|
|
40596
|
+
const position = compilationParams[2].getters.getCellPosition(cellId);
|
|
40597
|
+
return toXC(position.col, position.row);
|
|
40598
|
+
});
|
|
40599
|
+
compilationParams[2].__originSheetId = sheetId;
|
|
40600
|
+
return compiledFormula.execute(compiledFormula.dependencies, ...compilationParams);
|
|
40601
|
+
}
|
|
40346
40602
|
|
|
40347
40603
|
//#region
|
|
40348
40604
|
// ---------------------------------------------------------------------------
|
|
@@ -40437,7 +40693,6 @@ class PositionBitsEncoder {
|
|
|
40437
40693
|
// of other cells depending on it, at the next iteration.
|
|
40438
40694
|
//#endregion
|
|
40439
40695
|
class EvaluationPlugin extends UIPlugin {
|
|
40440
|
-
config;
|
|
40441
40696
|
static getters = [
|
|
40442
40697
|
"evaluateFormula",
|
|
40443
40698
|
"getCorrespondingFormulaCell",
|
|
@@ -40447,15 +40702,14 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
40447
40702
|
"getEvaluatedCell",
|
|
40448
40703
|
"getEvaluatedCells",
|
|
40449
40704
|
"getEvaluatedCellsInZone",
|
|
40705
|
+
"getSpreadPositionsOf",
|
|
40706
|
+
"getArrayFormulaSpreadingOn",
|
|
40450
40707
|
];
|
|
40451
40708
|
shouldRebuildDependenciesGraph = true;
|
|
40452
40709
|
evaluator;
|
|
40453
|
-
compilationParams;
|
|
40454
40710
|
positionsToUpdate = [];
|
|
40455
40711
|
constructor(config) {
|
|
40456
40712
|
super(config);
|
|
40457
|
-
this.config = config;
|
|
40458
|
-
this.compilationParams = this.getCompilationParameters();
|
|
40459
40713
|
this.evaluator = new Evaluator(config.custom, this.getters);
|
|
40460
40714
|
}
|
|
40461
40715
|
// ---------------------------------------------------------------------------
|
|
@@ -40480,10 +40734,6 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
40480
40734
|
case "EVALUATE_CELLS":
|
|
40481
40735
|
this.evaluator.evaluateAllCells();
|
|
40482
40736
|
break;
|
|
40483
|
-
case "UPDATE_LOCALE":
|
|
40484
|
-
this.compilationParams = this.getCompilationParameters();
|
|
40485
|
-
this.evaluator.updateCompilationParameters();
|
|
40486
|
-
break;
|
|
40487
40737
|
}
|
|
40488
40738
|
}
|
|
40489
40739
|
finalize() {
|
|
@@ -40501,16 +40751,7 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
40501
40751
|
// Getters
|
|
40502
40752
|
// ---------------------------------------------------------------------------
|
|
40503
40753
|
evaluateFormula(sheetId, formulaString) {
|
|
40504
|
-
|
|
40505
|
-
const ranges = [];
|
|
40506
|
-
for (let xc of compiledFormula.dependencies) {
|
|
40507
|
-
ranges.push(this.getters.getRangeFromSheetXC(sheetId, xc));
|
|
40508
|
-
}
|
|
40509
|
-
const array = compiledFormula.execute(ranges, ...this.compilationParams);
|
|
40510
|
-
if (isMatrix(array)) {
|
|
40511
|
-
return array.map((col) => col.map((row) => row.value));
|
|
40512
|
-
}
|
|
40513
|
-
return array.value;
|
|
40754
|
+
return this.evaluator.evaluateFormula(sheetId, formulaString);
|
|
40514
40755
|
}
|
|
40515
40756
|
/**
|
|
40516
40757
|
* Return the value of each cell in the range as they are displayed in the grid.
|
|
@@ -40556,6 +40797,12 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
40556
40797
|
getEvaluatedCellsInZone(sheetId, zone) {
|
|
40557
40798
|
return positions(zone).map(({ col, row }) => this.getters.getEvaluatedCell({ sheetId, col, row }));
|
|
40558
40799
|
}
|
|
40800
|
+
getSpreadPositionsOf(position) {
|
|
40801
|
+
return this.evaluator.getSpreadPositionsOf(position);
|
|
40802
|
+
}
|
|
40803
|
+
getArrayFormulaSpreadingOn(position) {
|
|
40804
|
+
return this.evaluator.getArrayFormulaSpreadingOn(position);
|
|
40805
|
+
}
|
|
40559
40806
|
// ---------------------------------------------------------------------------
|
|
40560
40807
|
// Export
|
|
40561
40808
|
// ---------------------------------------------------------------------------
|
|
@@ -40593,13 +40840,13 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
40593
40840
|
*/
|
|
40594
40841
|
getCorrespondingFormulaCell(position) {
|
|
40595
40842
|
const cell = this.getters.getCell(position);
|
|
40596
|
-
if (cell && cell.
|
|
40597
|
-
|
|
40598
|
-
|
|
40599
|
-
|
|
40843
|
+
if (cell && cell.isFormula) {
|
|
40844
|
+
return isBadExpression(cell.compiledFormula.tokens) ? undefined : cell;
|
|
40845
|
+
}
|
|
40846
|
+
else if (cell && cell.content) {
|
|
40600
40847
|
return undefined;
|
|
40601
40848
|
}
|
|
40602
|
-
const spreadingFormulaPosition = this.
|
|
40849
|
+
const spreadingFormulaPosition = this.getArrayFormulaSpreadingOn(position);
|
|
40603
40850
|
if (spreadingFormulaPosition === undefined) {
|
|
40604
40851
|
return undefined;
|
|
40605
40852
|
}
|
|
@@ -40609,13 +40856,10 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
40609
40856
|
}
|
|
40610
40857
|
return undefined;
|
|
40611
40858
|
}
|
|
40612
|
-
getCompilationParameters() {
|
|
40613
|
-
return buildCompilationParameters(this.config.custom, this.getters, (position) => this.evaluator.getEvaluatedCell(position));
|
|
40614
|
-
}
|
|
40615
40859
|
}
|
|
40616
|
-
function isBadExpression(
|
|
40860
|
+
function isBadExpression(tokens) {
|
|
40617
40861
|
try {
|
|
40618
|
-
|
|
40862
|
+
compileTokens(tokens);
|
|
40619
40863
|
return false;
|
|
40620
40864
|
}
|
|
40621
40865
|
catch (error) {
|
|
@@ -40784,22 +41028,20 @@ class EvaluationChartPlugin extends UIPlugin {
|
|
|
40784
41028
|
invalidateCFEvaluationCommands.has(cmd.type) ||
|
|
40785
41029
|
cmd.type === "EVALUATE_CELLS" ||
|
|
40786
41030
|
cmd.type === "UPDATE_CELL") {
|
|
40787
|
-
|
|
40788
|
-
|
|
40789
|
-
this.history.update("charts", chartId, undefined);
|
|
40790
|
-
}
|
|
41031
|
+
for (const chartId in this.charts) {
|
|
41032
|
+
this.charts[chartId] = undefined;
|
|
40791
41033
|
}
|
|
40792
41034
|
}
|
|
40793
41035
|
switch (cmd.type) {
|
|
40794
41036
|
case "UPDATE_CHART":
|
|
40795
41037
|
case "CREATE_CHART":
|
|
40796
41038
|
case "DELETE_FIGURE":
|
|
40797
|
-
this.
|
|
41039
|
+
this.charts[cmd.id] = undefined;
|
|
40798
41040
|
break;
|
|
40799
41041
|
case "DELETE_SHEET":
|
|
40800
41042
|
for (let chartId in this.charts) {
|
|
40801
41043
|
if (!this.getters.isChartDefined(chartId)) {
|
|
40802
|
-
this.
|
|
41044
|
+
this.charts[chartId] = undefined;
|
|
40803
41045
|
}
|
|
40804
41046
|
}
|
|
40805
41047
|
break;
|
|
@@ -40811,8 +41053,7 @@ class EvaluationChartPlugin extends UIPlugin {
|
|
|
40811
41053
|
if (!chart) {
|
|
40812
41054
|
throw new Error(`No chart for the given id: ${figureId}`);
|
|
40813
41055
|
}
|
|
40814
|
-
|
|
40815
|
-
this.history.update("charts", figureId, runtime);
|
|
41056
|
+
this.charts[figureId] = this.createRuntimeChart(chart);
|
|
40816
41057
|
}
|
|
40817
41058
|
return this.charts[figureId];
|
|
40818
41059
|
}
|
|
@@ -40964,7 +41205,10 @@ class EvaluationConditionalFormatPlugin extends UIPlugin {
|
|
|
40964
41205
|
const values = cf.rule.values.map((value, i) => {
|
|
40965
41206
|
const compiledFormula = formulas[i];
|
|
40966
41207
|
if (compiledFormula) {
|
|
40967
|
-
return this.getters.getTranslatedCellFormula(sheetId, col - zone.left, row - zone.top,
|
|
41208
|
+
return this.getters.getTranslatedCellFormula(sheetId, col - zone.left, row - zone.top, {
|
|
41209
|
+
...compiledFormula,
|
|
41210
|
+
dependencies: compiledFormula.dependencies.map((d) => this.getters.getRangeFromSheetXC(sheetId, d)),
|
|
41211
|
+
});
|
|
40968
41212
|
}
|
|
40969
41213
|
return value;
|
|
40970
41214
|
});
|
|
@@ -41336,7 +41580,10 @@ class EvaluationDataValidationPlugin extends UIPlugin {
|
|
|
41336
41580
|
}
|
|
41337
41581
|
try {
|
|
41338
41582
|
const formula = compile(value);
|
|
41339
|
-
const translatedFormula = this.getters.getTranslatedCellFormula(sheetId, offset.col, offset.row,
|
|
41583
|
+
const translatedFormula = this.getters.getTranslatedCellFormula(sheetId, offset.col, offset.row, {
|
|
41584
|
+
...formula,
|
|
41585
|
+
dependencies: formula.dependencies.map((d) => this.getters.getRangeFromSheetXC(sheetId, d)),
|
|
41586
|
+
});
|
|
41340
41587
|
const evaluated = this.getters.evaluateFormula(sheetId, translatedFormula);
|
|
41341
41588
|
return evaluated && !isMatrix(evaluated) ? evaluated.toString() : "";
|
|
41342
41589
|
}
|
|
@@ -43307,11 +43554,26 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
|
|
|
43307
43554
|
let cellsInRow = [];
|
|
43308
43555
|
for (let col of columnsIndex) {
|
|
43309
43556
|
const position = { col, row, sheetId };
|
|
43557
|
+
const spreader = getters.getArrayFormulaSpreadingOn(position);
|
|
43558
|
+
let cell = getters.getCell(position);
|
|
43559
|
+
const evaluatedCell = getters.getEvaluatedCell(position);
|
|
43560
|
+
if (spreader) {
|
|
43561
|
+
const isSpreaderCopied = rowsIndex.includes(spreader.row) && columnsIndex.includes(spreader.col);
|
|
43562
|
+
const content = isSpreaderCopied
|
|
43563
|
+
? ""
|
|
43564
|
+
: formatValue(evaluatedCell.value, { locale: getters.getLocale() });
|
|
43565
|
+
cell = {
|
|
43566
|
+
id: cell?.id || "",
|
|
43567
|
+
style: cell?.style,
|
|
43568
|
+
format: evaluatedCell.format,
|
|
43569
|
+
content,
|
|
43570
|
+
isFormula: false,
|
|
43571
|
+
};
|
|
43572
|
+
}
|
|
43310
43573
|
cellsInRow.push({
|
|
43311
|
-
cell
|
|
43312
|
-
style: getters.getCellComputedStyle(position),
|
|
43313
|
-
evaluatedCell: getters.getEvaluatedCell(position),
|
|
43574
|
+
cell,
|
|
43314
43575
|
border: getters.getCellBorder(position) || undefined,
|
|
43576
|
+
evaluatedCell,
|
|
43315
43577
|
position,
|
|
43316
43578
|
});
|
|
43317
43579
|
}
|
|
@@ -43433,13 +43695,6 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
|
|
|
43433
43695
|
});
|
|
43434
43696
|
}
|
|
43435
43697
|
this.pasteCopiedTables(target);
|
|
43436
|
-
this.cells.forEach((row) => {
|
|
43437
|
-
row.forEach((c) => {
|
|
43438
|
-
if (c.cell) {
|
|
43439
|
-
c.cell = undefined;
|
|
43440
|
-
}
|
|
43441
|
-
});
|
|
43442
|
-
});
|
|
43443
43698
|
}
|
|
43444
43699
|
/**
|
|
43445
43700
|
* The clipped zone is copied as many times as it fits in the target.
|
|
@@ -43513,7 +43768,7 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
|
|
|
43513
43768
|
clearClippedZones() {
|
|
43514
43769
|
for (const row of this.cells) {
|
|
43515
43770
|
for (const cell of row) {
|
|
43516
|
-
if (cell
|
|
43771
|
+
if (cell?.cell) {
|
|
43517
43772
|
this.dispatch("CLEAR_CELL", cell.position);
|
|
43518
43773
|
}
|
|
43519
43774
|
}
|
|
@@ -43539,6 +43794,9 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
|
|
|
43539
43794
|
const rowCells = this.cells[r];
|
|
43540
43795
|
for (let c = 0; c < width; c++) {
|
|
43541
43796
|
const origin = rowCells[c];
|
|
43797
|
+
if (!origin) {
|
|
43798
|
+
continue;
|
|
43799
|
+
}
|
|
43542
43800
|
const position = { col: col + c, row: row + r, sheetId: sheetId };
|
|
43543
43801
|
// TODO: refactor this part. the "Paste merge" action is also executed with
|
|
43544
43802
|
// MOVE_RANGES in pasteFromCut. Adding a condition on the operation type here
|
|
@@ -43562,53 +43820,42 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
|
|
|
43562
43820
|
pasteCell(origin, target, operation, clipboardOption) {
|
|
43563
43821
|
const { sheetId, col, row } = target;
|
|
43564
43822
|
const targetCell = this.getters.getEvaluatedCell(target);
|
|
43565
|
-
if (clipboardOption?.pasteOption
|
|
43566
|
-
const
|
|
43567
|
-
const
|
|
43568
|
-
|
|
43569
|
-
|
|
43570
|
-
bottom: targetBorders?.bottom || originBorders?.bottom,
|
|
43571
|
-
left: targetBorders?.left || originBorders?.left,
|
|
43572
|
-
right: targetBorders?.right || originBorders?.right,
|
|
43573
|
-
};
|
|
43574
|
-
this.dispatch("SET_BORDER", { sheetId, col, row, border });
|
|
43823
|
+
if (clipboardOption?.pasteOption === "onlyValue") {
|
|
43824
|
+
const locale = this.getters.getLocale();
|
|
43825
|
+
const content = formatValue(origin.evaluatedCell.value, { locale });
|
|
43826
|
+
this.dispatch("UPDATE_CELL", { ...target, content });
|
|
43827
|
+
return;
|
|
43575
43828
|
}
|
|
43576
|
-
|
|
43577
|
-
|
|
43578
|
-
|
|
43579
|
-
|
|
43580
|
-
|
|
43581
|
-
|
|
43582
|
-
|
|
43583
|
-
|
|
43584
|
-
|
|
43585
|
-
|
|
43586
|
-
|
|
43587
|
-
|
|
43588
|
-
|
|
43589
|
-
|
|
43590
|
-
}
|
|
43591
|
-
|
|
43592
|
-
|
|
43593
|
-
|
|
43594
|
-
|
|
43829
|
+
const targetBorders = this.getters.getCellBorder(target);
|
|
43830
|
+
const originBorders = origin.border;
|
|
43831
|
+
const border = {
|
|
43832
|
+
top: targetBorders?.top || originBorders?.top,
|
|
43833
|
+
bottom: targetBorders?.bottom || originBorders?.bottom,
|
|
43834
|
+
left: targetBorders?.left || originBorders?.left,
|
|
43835
|
+
right: targetBorders?.right || originBorders?.right,
|
|
43836
|
+
};
|
|
43837
|
+
this.dispatch("SET_BORDER", { sheetId, col, row, border });
|
|
43838
|
+
if (clipboardOption?.pasteOption === "onlyFormat") {
|
|
43839
|
+
this.dispatch("UPDATE_CELL", {
|
|
43840
|
+
...target,
|
|
43841
|
+
style: origin.cell?.style ?? null,
|
|
43842
|
+
format: origin.cell?.format ?? origin.evaluatedCell.format ?? targetCell.format,
|
|
43843
|
+
});
|
|
43844
|
+
return;
|
|
43845
|
+
}
|
|
43846
|
+
const content = origin.cell && origin.cell.isFormula && operation === "COPY"
|
|
43847
|
+
? this.getters.getTranslatedCellFormula(sheetId, col - origin.position.col, row - origin.position.row, origin.cell.compiledFormula)
|
|
43848
|
+
: origin.cell?.content;
|
|
43849
|
+
if (content !== "" || origin.cell?.format || origin.cell?.style) {
|
|
43595
43850
|
this.dispatch("UPDATE_CELL", {
|
|
43596
43851
|
...target,
|
|
43597
43852
|
content,
|
|
43598
|
-
style: origin.cell
|
|
43599
|
-
format: origin.cell
|
|
43853
|
+
style: origin.cell?.style || null,
|
|
43854
|
+
format: origin.cell?.format,
|
|
43600
43855
|
});
|
|
43601
43856
|
}
|
|
43602
43857
|
else if (targetCell) {
|
|
43603
|
-
|
|
43604
|
-
this.dispatch("UPDATE_CELL", { ...target, content: "" });
|
|
43605
|
-
}
|
|
43606
|
-
else if (clipboardOption?.pasteOption === "onlyFormat") {
|
|
43607
|
-
this.dispatch("UPDATE_CELL", { ...target, style: null, format: "" });
|
|
43608
|
-
}
|
|
43609
|
-
else {
|
|
43610
|
-
this.dispatch("CLEAR_CELL", target);
|
|
43611
|
-
}
|
|
43858
|
+
this.dispatch("CLEAR_CELL", target);
|
|
43612
43859
|
}
|
|
43613
43860
|
}
|
|
43614
43861
|
/**
|
|
@@ -43670,22 +43917,28 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
|
|
|
43670
43917
|
return (this.cells
|
|
43671
43918
|
.map((cells) => {
|
|
43672
43919
|
return cells
|
|
43673
|
-
.map((c) => this.getters.shouldShowFormulas() && c
|
|
43920
|
+
.map((c) => this.getters.shouldShowFormulas() && c?.cell?.isFormula
|
|
43674
43921
|
? c.cell?.content || ""
|
|
43675
|
-
: c
|
|
43922
|
+
: c?.evaluatedCell?.formattedValue || "")
|
|
43676
43923
|
.join("\t");
|
|
43677
43924
|
})
|
|
43678
43925
|
.join("\n") || "\t");
|
|
43679
43926
|
}
|
|
43680
43927
|
getHTMLContent() {
|
|
43681
43928
|
if (this.cells.length === 1 && this.cells[0].length === 1) {
|
|
43929
|
+
if (!this.cells[0][0]) {
|
|
43930
|
+
return "";
|
|
43931
|
+
}
|
|
43682
43932
|
return this.getters.getCellText(this.cells[0][0].position);
|
|
43683
43933
|
}
|
|
43684
43934
|
let htmlTable = '<table border="1" style="border-collapse:collapse">';
|
|
43685
43935
|
for (const row of this.cells) {
|
|
43686
43936
|
htmlTable += "<tr>";
|
|
43687
43937
|
for (const cell of row) {
|
|
43688
|
-
|
|
43938
|
+
if (!cell) {
|
|
43939
|
+
continue;
|
|
43940
|
+
}
|
|
43941
|
+
const cssStyle = cssPropertiesToCss(cellStyleToCss(this.getters.getCellComputedStyle(cell.position)));
|
|
43689
43942
|
const cellText = this.getters.getCellText(cell.position);
|
|
43690
43943
|
htmlTable += `<td style="${cssStyle}">` + xmlEscape(cellText) + "</td>";
|
|
43691
43944
|
}
|
|
@@ -44013,24 +44266,49 @@ var Direction;
|
|
|
44013
44266
|
*/
|
|
44014
44267
|
class FindAndReplacePlugin extends UIPlugin {
|
|
44015
44268
|
static layers = [3 /* LAYERS.Search */];
|
|
44016
|
-
static getters = [
|
|
44017
|
-
|
|
44269
|
+
static getters = [
|
|
44270
|
+
"getSearchMatches",
|
|
44271
|
+
"getCurrentSelectedMatchIndex",
|
|
44272
|
+
"getSearchOptions",
|
|
44273
|
+
"getAllSheetMatchesCount",
|
|
44274
|
+
"getActiveSheetMatchesCount",
|
|
44275
|
+
"getSpecificRangeMatchesCount",
|
|
44276
|
+
];
|
|
44277
|
+
allSheetsMatches = [];
|
|
44278
|
+
activeSheetMatches = [];
|
|
44279
|
+
specificRangeMatches = [];
|
|
44280
|
+
// fixme: why do we make selectedMatchIndex on top of a selected
|
|
44281
|
+
// property in the matches?
|
|
44018
44282
|
selectedMatchIndex = null;
|
|
44019
44283
|
currentSearchRegex = null;
|
|
44020
44284
|
searchOptions = {
|
|
44021
44285
|
matchCase: false,
|
|
44022
44286
|
exactMatch: false,
|
|
44023
44287
|
searchFormulas: false,
|
|
44288
|
+
searchScope: "allSheets",
|
|
44289
|
+
specificRange: undefined,
|
|
44024
44290
|
};
|
|
44025
44291
|
toSearch = "";
|
|
44026
44292
|
isSearchDirty = false;
|
|
44293
|
+
get searchMatches() {
|
|
44294
|
+
switch (this.searchOptions.searchScope) {
|
|
44295
|
+
case "allSheets":
|
|
44296
|
+
return this.allSheetsMatches;
|
|
44297
|
+
case "activeSheet":
|
|
44298
|
+
return this.activeSheetMatches;
|
|
44299
|
+
case "specificRange":
|
|
44300
|
+
return this.specificRangeMatches;
|
|
44301
|
+
}
|
|
44302
|
+
}
|
|
44027
44303
|
// ---------------------------------------------------------------------------
|
|
44028
44304
|
// Command Handling
|
|
44029
44305
|
// ---------------------------------------------------------------------------
|
|
44030
44306
|
handle(cmd) {
|
|
44031
44307
|
switch (cmd.type) {
|
|
44032
44308
|
case "UPDATE_SEARCH":
|
|
44033
|
-
|
|
44309
|
+
const rangeData = cmd.searchOptions.specificRange;
|
|
44310
|
+
const specificRange = rangeData && this.getters.getRangeFromRangeData(rangeData);
|
|
44311
|
+
this.updateSearch(cmd.toSearch, { ...cmd.searchOptions, specificRange });
|
|
44034
44312
|
break;
|
|
44035
44313
|
case "CLEAR_SEARCH":
|
|
44036
44314
|
this.clearSearch();
|
|
@@ -44060,7 +44338,9 @@ class FindAndReplacePlugin extends UIPlugin {
|
|
|
44060
44338
|
this.isSearchDirty = true;
|
|
44061
44339
|
break;
|
|
44062
44340
|
case "ACTIVATE_SHEET":
|
|
44063
|
-
this.
|
|
44341
|
+
if (this.searchOptions.searchScope === "activeSheet") {
|
|
44342
|
+
this.isSearchDirty = true;
|
|
44343
|
+
}
|
|
44064
44344
|
break;
|
|
44065
44345
|
}
|
|
44066
44346
|
}
|
|
@@ -44079,6 +44359,18 @@ class FindAndReplacePlugin extends UIPlugin {
|
|
|
44079
44359
|
getCurrentSelectedMatchIndex() {
|
|
44080
44360
|
return this.selectedMatchIndex;
|
|
44081
44361
|
}
|
|
44362
|
+
getSearchOptions() {
|
|
44363
|
+
return { ...this.searchOptions, specificRange: this.searchOptions.specificRange?.rangeData };
|
|
44364
|
+
}
|
|
44365
|
+
getAllSheetMatchesCount() {
|
|
44366
|
+
return this.allSheetsMatches.length;
|
|
44367
|
+
}
|
|
44368
|
+
getActiveSheetMatchesCount() {
|
|
44369
|
+
return this.activeSheetMatches.length;
|
|
44370
|
+
}
|
|
44371
|
+
getSpecificRangeMatchesCount() {
|
|
44372
|
+
return this.specificRangeMatches.length;
|
|
44373
|
+
}
|
|
44082
44374
|
// ---------------------------------------------------------------------------
|
|
44083
44375
|
// Search
|
|
44084
44376
|
// ---------------------------------------------------------------------------
|
|
@@ -44099,8 +44391,8 @@ class FindAndReplacePlugin extends UIPlugin {
|
|
|
44099
44391
|
* refresh the matches according to the current search options
|
|
44100
44392
|
*/
|
|
44101
44393
|
refreshSearch() {
|
|
44102
|
-
|
|
44103
|
-
this.
|
|
44394
|
+
this.selectedMatchIndex = null;
|
|
44395
|
+
this.findMatches();
|
|
44104
44396
|
this.selectNextCell(Direction.current);
|
|
44105
44397
|
}
|
|
44106
44398
|
/**
|
|
@@ -44115,36 +44407,65 @@ class FindAndReplacePlugin extends UIPlugin {
|
|
|
44115
44407
|
}
|
|
44116
44408
|
this.currentSearchRegex = RegExp(searchValue, flags);
|
|
44117
44409
|
}
|
|
44410
|
+
getSheetsInSearchOrder() {
|
|
44411
|
+
switch (this.searchOptions.searchScope) {
|
|
44412
|
+
case "allSheets":
|
|
44413
|
+
const sheetIds = this.getters.getSheetIds();
|
|
44414
|
+
const activeSheetIndex = sheetIds.findIndex((id) => id === this.getters.getActiveSheetId());
|
|
44415
|
+
return [
|
|
44416
|
+
sheetIds[activeSheetIndex],
|
|
44417
|
+
...sheetIds.slice(activeSheetIndex + 1),
|
|
44418
|
+
...sheetIds.slice(0, activeSheetIndex),
|
|
44419
|
+
];
|
|
44420
|
+
case "activeSheet":
|
|
44421
|
+
return [this.getters.getActiveSheetId()];
|
|
44422
|
+
case "specificRange":
|
|
44423
|
+
const specificRange = this.searchOptions.specificRange;
|
|
44424
|
+
if (!specificRange) {
|
|
44425
|
+
return [];
|
|
44426
|
+
}
|
|
44427
|
+
return specificRange ? [specificRange.sheetId] : [];
|
|
44428
|
+
}
|
|
44429
|
+
}
|
|
44118
44430
|
/**
|
|
44119
44431
|
* Find matches using the current regex
|
|
44120
44432
|
*/
|
|
44121
44433
|
findMatches() {
|
|
44122
|
-
const sheetId = this.getters.getActiveSheetId();
|
|
44123
|
-
const cells = this.getters.getCells(sheetId);
|
|
44124
44434
|
const matches = [];
|
|
44125
44435
|
if (this.toSearch) {
|
|
44126
|
-
for (const
|
|
44127
|
-
|
|
44436
|
+
for (const sheetId of this.getters.getSheetIds()) {
|
|
44437
|
+
matches.push(...this.findMatchesInSheet(sheetId));
|
|
44438
|
+
}
|
|
44439
|
+
}
|
|
44440
|
+
// set results
|
|
44441
|
+
this.allSheetsMatches = matches;
|
|
44442
|
+
this.activeSheetMatches = matches.filter((match) => match.sheetId === this.getters.getActiveSheetId());
|
|
44443
|
+
if (this.searchOptions.specificRange) {
|
|
44444
|
+
const { sheetId, zone } = this.searchOptions.specificRange;
|
|
44445
|
+
this.specificRangeMatches = matches.filter((match) => match.sheetId === sheetId && isInside(match.col, match.row, zone));
|
|
44446
|
+
}
|
|
44447
|
+
else {
|
|
44448
|
+
this.specificRangeMatches = [];
|
|
44449
|
+
}
|
|
44450
|
+
}
|
|
44451
|
+
findMatchesInSheet(sheetId) {
|
|
44452
|
+
const matches = [];
|
|
44453
|
+
const { left, right, top, bottom } = this.getters.getSheetZone(sheetId);
|
|
44454
|
+
for (let row = top; row <= bottom; row++) {
|
|
44455
|
+
for (let col = left; col <= right; col++) {
|
|
44128
44456
|
const isColHidden = this.getters.isColHidden(sheetId, col);
|
|
44129
44457
|
const isRowHidden = this.getters.isRowHidden(sheetId, row);
|
|
44130
44458
|
if (isColHidden || isRowHidden) {
|
|
44131
44459
|
continue;
|
|
44132
44460
|
}
|
|
44133
|
-
|
|
44134
|
-
|
|
44135
|
-
|
|
44136
|
-
const match = { col, row, selected: false };
|
|
44461
|
+
const cellPosition = { sheetId, col, row };
|
|
44462
|
+
if (this.currentSearchRegex?.test(this.getSearchableString(cellPosition))) {
|
|
44463
|
+
const match = { sheetId, col, row };
|
|
44137
44464
|
matches.push(match);
|
|
44138
44465
|
}
|
|
44139
44466
|
}
|
|
44140
44467
|
}
|
|
44141
|
-
return matches
|
|
44142
|
-
}
|
|
44143
|
-
sortByRowThenColumn(a, b) {
|
|
44144
|
-
if (a.row === b.row) {
|
|
44145
|
-
return a.col - b.col;
|
|
44146
|
-
}
|
|
44147
|
-
return a.row > b.row ? 1 : -1;
|
|
44468
|
+
return matches;
|
|
44148
44469
|
}
|
|
44149
44470
|
/**
|
|
44150
44471
|
* Changes the selected search cell. Given a direction it will
|
|
@@ -44162,30 +44483,47 @@ class FindAndReplacePlugin extends UIPlugin {
|
|
|
44162
44483
|
}
|
|
44163
44484
|
let nextIndex;
|
|
44164
44485
|
if (this.selectedMatchIndex === null) {
|
|
44165
|
-
|
|
44486
|
+
let nextMatchIndex = -1;
|
|
44487
|
+
// if search is not available in current sheet will select in next sheet
|
|
44488
|
+
for (const sheetId of this.getSheetsInSearchOrder()) {
|
|
44489
|
+
nextMatchIndex = matches.findIndex((match) => match.sheetId === sheetId);
|
|
44490
|
+
if (nextMatchIndex !== -1) {
|
|
44491
|
+
break;
|
|
44492
|
+
}
|
|
44493
|
+
}
|
|
44494
|
+
nextIndex = nextMatchIndex;
|
|
44166
44495
|
}
|
|
44167
44496
|
else {
|
|
44168
44497
|
nextIndex = this.selectedMatchIndex + indexChange;
|
|
44169
44498
|
}
|
|
44170
|
-
//
|
|
44171
|
-
nextIndex = (
|
|
44499
|
+
// loop index value inside the array (index -1 => last index)
|
|
44500
|
+
nextIndex = (nextIndex + matches.length) % matches.length;
|
|
44172
44501
|
this.selectedMatchIndex = nextIndex;
|
|
44502
|
+
const selectedMatch = matches[nextIndex];
|
|
44503
|
+
// Switch to the sheet where the match is located
|
|
44504
|
+
if (this.getters.getActiveSheetId() !== selectedMatch.sheetId) {
|
|
44505
|
+
this.dispatch("ACTIVATE_SHEET", {
|
|
44506
|
+
sheetIdFrom: this.getters.getActiveSheetId(),
|
|
44507
|
+
sheetIdTo: selectedMatch.sheetId,
|
|
44508
|
+
});
|
|
44509
|
+
}
|
|
44173
44510
|
// we want grid selection to capture the selection stream
|
|
44174
44511
|
this.selection.getBackToDefault();
|
|
44175
|
-
this.selection.selectCell(
|
|
44176
|
-
for (let index = 0; index < this.searchMatches.length; index++) {
|
|
44177
|
-
this.searchMatches[index].selected = index === this.selectedMatchIndex;
|
|
44178
|
-
}
|
|
44512
|
+
this.selection.selectCell(selectedMatch.col, selectedMatch.row);
|
|
44179
44513
|
}
|
|
44180
44514
|
clearSearch() {
|
|
44181
44515
|
this.toSearch = "";
|
|
44182
|
-
this.searchMatches = [];
|
|
44183
44516
|
this.selectedMatchIndex = null;
|
|
44184
44517
|
this.currentSearchRegex = null;
|
|
44518
|
+
this.allSheetsMatches = [];
|
|
44519
|
+
this.activeSheetMatches = [];
|
|
44520
|
+
this.specificRangeMatches = [];
|
|
44185
44521
|
this.searchOptions = {
|
|
44186
44522
|
matchCase: false,
|
|
44187
44523
|
exactMatch: false,
|
|
44188
44524
|
searchFormulas: false,
|
|
44525
|
+
searchScope: "allSheets",
|
|
44526
|
+
specificRange: undefined,
|
|
44189
44527
|
};
|
|
44190
44528
|
}
|
|
44191
44529
|
// ---------------------------------------------------------------------------
|
|
@@ -44195,17 +44533,18 @@ class FindAndReplacePlugin extends UIPlugin {
|
|
|
44195
44533
|
if (!this.currentSearchRegex) {
|
|
44196
44534
|
return;
|
|
44197
44535
|
}
|
|
44198
|
-
const
|
|
44199
|
-
|
|
44200
|
-
|
|
44536
|
+
const cell = this.getters.getCell(selectedMatch);
|
|
44537
|
+
if (!cell?.content) {
|
|
44538
|
+
return;
|
|
44539
|
+
}
|
|
44201
44540
|
if (cell?.isFormula && !this.searchOptions.searchFormulas) {
|
|
44202
44541
|
return;
|
|
44203
44542
|
}
|
|
44204
44543
|
const replaceRegex = new RegExp(this.currentSearchRegex.source, this.currentSearchRegex.flags + "g");
|
|
44205
|
-
const toReplace = this.getSearchableString(
|
|
44544
|
+
const toReplace = this.getSearchableString(selectedMatch);
|
|
44206
44545
|
const content = toReplace.replace(replaceRegex, replaceWith);
|
|
44207
44546
|
const canonicalContent = canonicalizeNumberContent(content, this.getters.getLocale());
|
|
44208
|
-
this.dispatch("UPDATE_CELL", {
|
|
44547
|
+
this.dispatch("UPDATE_CELL", { ...selectedMatch, content: canonicalContent });
|
|
44209
44548
|
}
|
|
44210
44549
|
/**
|
|
44211
44550
|
* Replace the value of the currently selected match
|
|
@@ -44236,7 +44575,10 @@ class FindAndReplacePlugin extends UIPlugin {
|
|
|
44236
44575
|
drawGrid(renderingContext) {
|
|
44237
44576
|
const { ctx } = renderingContext;
|
|
44238
44577
|
const sheetId = this.getters.getActiveSheetId();
|
|
44239
|
-
for (const match of this.searchMatches) {
|
|
44578
|
+
for (const [index, match] of this.searchMatches.entries()) {
|
|
44579
|
+
if (match.sheetId !== sheetId) {
|
|
44580
|
+
continue; // Skip drawing matches from other sheets
|
|
44581
|
+
}
|
|
44240
44582
|
const merge = this.getters.getMerge({ sheetId, col: match.col, row: match.row });
|
|
44241
44583
|
const left = merge ? merge.left : match.col;
|
|
44242
44584
|
const right = merge ? merge.right : match.col;
|
|
@@ -44246,12 +44588,21 @@ class FindAndReplacePlugin extends UIPlugin {
|
|
|
44246
44588
|
if (width > 0 && height > 0) {
|
|
44247
44589
|
ctx.fillStyle = BACKGROUND_COLOR;
|
|
44248
44590
|
ctx.fillRect(x, y, width, height);
|
|
44249
|
-
if (
|
|
44591
|
+
if (index === this.selectedMatchIndex) {
|
|
44250
44592
|
ctx.strokeStyle = BORDER_COLOR;
|
|
44251
44593
|
ctx.strokeRect(x, y, width, height);
|
|
44252
44594
|
}
|
|
44253
44595
|
}
|
|
44254
44596
|
}
|
|
44597
|
+
if (this.searchOptions.searchScope === "specificRange") {
|
|
44598
|
+
const range = this.searchOptions.specificRange;
|
|
44599
|
+
if (!range || range.sheetId !== sheetId) {
|
|
44600
|
+
return;
|
|
44601
|
+
}
|
|
44602
|
+
const { x, y, width, height } = this.getters.getVisibleRect(range.zone);
|
|
44603
|
+
ctx.strokeStyle = BORDER_COLOR;
|
|
44604
|
+
ctx.strokeRect(x, y, width, height);
|
|
44605
|
+
}
|
|
44255
44606
|
}
|
|
44256
44607
|
}
|
|
44257
44608
|
|
|
@@ -45534,7 +45885,6 @@ class SelectionInputsManagerPlugin extends UIPlugin {
|
|
|
45534
45885
|
}
|
|
45535
45886
|
|
|
45536
45887
|
class SortPlugin extends UIPlugin {
|
|
45537
|
-
static getters = ["getContiguousZone"];
|
|
45538
45888
|
allowDispatch(cmd) {
|
|
45539
45889
|
switch (cmd.type) {
|
|
45540
45890
|
case "SORT_CELLS":
|
|
@@ -45582,143 +45932,6 @@ class SortPlugin extends UIPlugin {
|
|
|
45582
45932
|
}
|
|
45583
45933
|
return "Success" /* CommandResult.Success */;
|
|
45584
45934
|
}
|
|
45585
|
-
// getContiguousZone helpers
|
|
45586
|
-
/**
|
|
45587
|
-
* safe-version of expandZone to make sure we don't get out of the grid
|
|
45588
|
-
*/
|
|
45589
|
-
expand(sheetId, z) {
|
|
45590
|
-
const { left, right, top, bottom } = this.getters.expandZone(sheetId, z);
|
|
45591
|
-
return {
|
|
45592
|
-
left: Math.max(0, left),
|
|
45593
|
-
right: Math.min(this.getters.getNumberCols(sheetId) - 1, right),
|
|
45594
|
-
top: Math.max(0, top),
|
|
45595
|
-
bottom: Math.min(this.getters.getNumberRows(sheetId) - 1, bottom),
|
|
45596
|
-
};
|
|
45597
|
-
}
|
|
45598
|
-
/**
|
|
45599
|
-
* verifies the presence of at least one non-empty cell in the given zone
|
|
45600
|
-
*/
|
|
45601
|
-
checkExpandedValues(sheetId, z) {
|
|
45602
|
-
const expandedZone = this.expand(sheetId, z);
|
|
45603
|
-
let cell;
|
|
45604
|
-
if (this.getters.doesIntersectMerge(sheetId, expandedZone)) {
|
|
45605
|
-
const { left, right, top, bottom } = expandedZone;
|
|
45606
|
-
for (let c = left; c <= right; c++) {
|
|
45607
|
-
for (let r = top; r <= bottom; r++) {
|
|
45608
|
-
const { col, row } = this.getters.getMainCellPosition({ sheetId, col: c, row: r });
|
|
45609
|
-
cell = this.getters.getEvaluatedCell({ sheetId, col, row });
|
|
45610
|
-
if (cell.formattedValue) {
|
|
45611
|
-
return true;
|
|
45612
|
-
}
|
|
45613
|
-
}
|
|
45614
|
-
}
|
|
45615
|
-
}
|
|
45616
|
-
else {
|
|
45617
|
-
for (let cell of this.getters.getEvaluatedCellsInZone(sheetId, expandedZone)) {
|
|
45618
|
-
if (cell.formattedValue) {
|
|
45619
|
-
return true;
|
|
45620
|
-
}
|
|
45621
|
-
}
|
|
45622
|
-
}
|
|
45623
|
-
return false;
|
|
45624
|
-
}
|
|
45625
|
-
/**
|
|
45626
|
-
* This function will expand the provided zone in directions (top, bottom, left, right) for which there
|
|
45627
|
-
* are non-null cells on the external boundary of the zone in the given direction.
|
|
45628
|
-
*
|
|
45629
|
-
* Example:
|
|
45630
|
-
* A B C D E
|
|
45631
|
-
* ___ ___ ___ ___ ___
|
|
45632
|
-
* 1 | | D | | | |
|
|
45633
|
-
* ___ ___ ___ ___ ___
|
|
45634
|
-
* 2 | 5 | | 1 | D | |
|
|
45635
|
-
* ___ ___ ___ ___ ___
|
|
45636
|
-
* 3 | | | A | X | |
|
|
45637
|
-
* ___ ___ ___ ___ ___
|
|
45638
|
-
* 4 | | | | | |
|
|
45639
|
-
* ___ ___ ___ ___ ___
|
|
45640
|
-
*
|
|
45641
|
-
* Let's consider a provided zone corresponding to (C2:D3) - (left:2, right: 3, top:1, bottom:2)
|
|
45642
|
-
* - the top external boundary is (B1:E1)
|
|
45643
|
-
* Since we have B1='D' != "", we expand to the top: => (C1:D3)
|
|
45644
|
-
* The top boundary having reached the top of the grid, we cannot expand in that direction anymore
|
|
45645
|
-
*
|
|
45646
|
-
* - the left boundary is (B1:B4)
|
|
45647
|
-
* since we have B1 again, we expand to the left => (B1:D3)
|
|
45648
|
-
*
|
|
45649
|
-
* - the right and bottom boundaries are a dead end for now as (E1:E4) and (A4:E4) are empty.
|
|
45650
|
-
*
|
|
45651
|
-
* - the left boundary is now (A1:A4)
|
|
45652
|
-
* Since we have A2=5 != "", we can therefore expand to the left => (A1:D3)
|
|
45653
|
-
*
|
|
45654
|
-
* This will be the final zone as left and top have reached the boundaries of the grid and
|
|
45655
|
-
* the other boundaries (E1:E4) and (A4:E4) are empty.
|
|
45656
|
-
*
|
|
45657
|
-
* @param sheetId UID of concerned sheet
|
|
45658
|
-
* @param zone Zone
|
|
45659
|
-
*
|
|
45660
|
-
*/
|
|
45661
|
-
getContiguousZone(sheetId, zone) {
|
|
45662
|
-
let { top, bottom, left, right } = zone;
|
|
45663
|
-
let canExpand;
|
|
45664
|
-
let stop = false;
|
|
45665
|
-
while (!stop) {
|
|
45666
|
-
stop = true;
|
|
45667
|
-
/** top row external boundary */
|
|
45668
|
-
if (top > 0) {
|
|
45669
|
-
canExpand = this.checkExpandedValues(sheetId, {
|
|
45670
|
-
left: left - 1,
|
|
45671
|
-
right: right + 1,
|
|
45672
|
-
top: top - 1,
|
|
45673
|
-
bottom: top - 1,
|
|
45674
|
-
});
|
|
45675
|
-
if (canExpand) {
|
|
45676
|
-
stop = false;
|
|
45677
|
-
top--;
|
|
45678
|
-
}
|
|
45679
|
-
}
|
|
45680
|
-
/** left column external boundary */
|
|
45681
|
-
if (left > 0) {
|
|
45682
|
-
canExpand = this.checkExpandedValues(sheetId, {
|
|
45683
|
-
left: left - 1,
|
|
45684
|
-
right: left - 1,
|
|
45685
|
-
top: top - 1,
|
|
45686
|
-
bottom: bottom + 1,
|
|
45687
|
-
});
|
|
45688
|
-
if (canExpand) {
|
|
45689
|
-
stop = false;
|
|
45690
|
-
left--;
|
|
45691
|
-
}
|
|
45692
|
-
}
|
|
45693
|
-
/** right column external boundary */
|
|
45694
|
-
if (right < this.getters.getNumberCols(sheetId) - 1) {
|
|
45695
|
-
canExpand = this.checkExpandedValues(sheetId, {
|
|
45696
|
-
left: right + 1,
|
|
45697
|
-
right: right + 1,
|
|
45698
|
-
top: top - 1,
|
|
45699
|
-
bottom: bottom + 1,
|
|
45700
|
-
});
|
|
45701
|
-
if (canExpand) {
|
|
45702
|
-
stop = false;
|
|
45703
|
-
right++;
|
|
45704
|
-
}
|
|
45705
|
-
}
|
|
45706
|
-
/** bottom row external boundary */
|
|
45707
|
-
if (bottom < this.getters.getNumberRows(sheetId) - 1) {
|
|
45708
|
-
canExpand = this.checkExpandedValues(sheetId, {
|
|
45709
|
-
left: left - 1,
|
|
45710
|
-
right: right + 1,
|
|
45711
|
-
top: bottom + 1,
|
|
45712
|
-
bottom: bottom + 1,
|
|
45713
|
-
});
|
|
45714
|
-
if (canExpand) {
|
|
45715
|
-
stop = false;
|
|
45716
|
-
bottom++;
|
|
45717
|
-
}
|
|
45718
|
-
}
|
|
45719
|
-
}
|
|
45720
|
-
return { left, right, top, bottom };
|
|
45721
|
-
}
|
|
45722
45935
|
/**
|
|
45723
45936
|
* This function evaluates if the top row of a provided zone can be considered as a `header`
|
|
45724
45937
|
* by checking the following criteria:
|
|
@@ -45783,7 +45996,7 @@ class SortPlugin extends UIPlugin {
|
|
|
45783
45996
|
if (cell.isFormula) {
|
|
45784
45997
|
const position = this.getters.getCellPosition(cell.id);
|
|
45785
45998
|
// we only have a vertical offset
|
|
45786
|
-
content = this.getters.getTranslatedCellFormula(sheetId, 0, newRow - position.row, cell.compiledFormula
|
|
45999
|
+
content = this.getters.getTranslatedCellFormula(sheetId, 0, newRow - position.row, cell.compiledFormula);
|
|
45787
46000
|
}
|
|
45788
46001
|
newCellValues.style = cell.style;
|
|
45789
46002
|
newCellValues.content = content;
|
|
@@ -45852,6 +46065,8 @@ class SheetUIPlugin extends UIPlugin {
|
|
|
45852
46065
|
"getTextWidth",
|
|
45853
46066
|
"getCellText",
|
|
45854
46067
|
"getCellMultiLineText",
|
|
46068
|
+
"getContiguousZone",
|
|
46069
|
+
"isCellEmpty",
|
|
45855
46070
|
];
|
|
45856
46071
|
ctx = document.createElement("canvas").getContext("2d");
|
|
45857
46072
|
// ---------------------------------------------------------------------------
|
|
@@ -45941,9 +46156,52 @@ class SheetUIPlugin extends UIPlugin {
|
|
|
45941
46156
|
const hasListIcon = !this.getters.isReadonly() && this.getters.cellHasListDataValidationIcon(position);
|
|
45942
46157
|
return isFilterHeader || hasListIcon;
|
|
45943
46158
|
}
|
|
45944
|
-
|
|
45945
|
-
|
|
45946
|
-
|
|
46159
|
+
/**
|
|
46160
|
+
* Expands the given zone until bordered by empty cells or reached the sheet boundaries.
|
|
46161
|
+
*/
|
|
46162
|
+
getContiguousZone(sheetId, zoneToExpand) {
|
|
46163
|
+
/** Try to expand the zone by one col/row in any direction to include a new non-empty cell */
|
|
46164
|
+
const expandZone = (zone) => {
|
|
46165
|
+
for (const col of range(zone.left, zone.right + 1)) {
|
|
46166
|
+
if (!this.isCellEmpty({ sheetId, col, row: zone.top - 1 })) {
|
|
46167
|
+
return { ...zone, top: zone.top - 1 };
|
|
46168
|
+
}
|
|
46169
|
+
if (!this.isCellEmpty({ sheetId, col, row: zone.bottom + 1 })) {
|
|
46170
|
+
return { ...zone, bottom: zone.bottom + 1 };
|
|
46171
|
+
}
|
|
46172
|
+
}
|
|
46173
|
+
for (const row of range(zone.top, zone.bottom + 1)) {
|
|
46174
|
+
if (!this.isCellEmpty({ sheetId, col: zone.left - 1, row })) {
|
|
46175
|
+
return { ...zone, left: zone.left - 1 };
|
|
46176
|
+
}
|
|
46177
|
+
if (!this.isCellEmpty({ sheetId, col: zone.right + 1, row })) {
|
|
46178
|
+
return { ...zone, right: zone.right + 1 };
|
|
46179
|
+
}
|
|
46180
|
+
}
|
|
46181
|
+
return zone;
|
|
46182
|
+
};
|
|
46183
|
+
let hasExpanded = false;
|
|
46184
|
+
let zone = zoneToExpand;
|
|
46185
|
+
do {
|
|
46186
|
+
hasExpanded = false;
|
|
46187
|
+
const newZone = expandZone(zone);
|
|
46188
|
+
if (!isEqual(zone, newZone)) {
|
|
46189
|
+
hasExpanded = true;
|
|
46190
|
+
zone = newZone;
|
|
46191
|
+
continue;
|
|
46192
|
+
}
|
|
46193
|
+
} while (hasExpanded);
|
|
46194
|
+
return zone;
|
|
46195
|
+
}
|
|
46196
|
+
/**
|
|
46197
|
+
* Check if a cell is empty. If the cell is part of a merge,
|
|
46198
|
+
* check if the merge containing the cell is empty.
|
|
46199
|
+
*/
|
|
46200
|
+
isCellEmpty(position) {
|
|
46201
|
+
const mainPosition = this.getters.getMainCellPosition(position);
|
|
46202
|
+
const cell = this.getters.getEvaluatedCell(mainPosition);
|
|
46203
|
+
return cell.type === CellValueType.empty;
|
|
46204
|
+
}
|
|
45947
46205
|
getColMaxWidth(sheetId, index) {
|
|
45948
46206
|
const cellsPositions = positions(this.getters.getColsZone(sheetId, index, index));
|
|
45949
46207
|
const sizes = cellsPositions.map((position) => this.getCellWidth({ sheetId, ...position }));
|
|
@@ -46810,11 +47068,14 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
46810
47068
|
}
|
|
46811
47069
|
const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
|
|
46812
47070
|
this.state.paste(cmd.target, { pasteOption, shouldPasteCF: true, selectTarget: true });
|
|
47071
|
+
if (this.state.operation === "CUT") {
|
|
47072
|
+
this.state = undefined;
|
|
47073
|
+
}
|
|
46813
47074
|
this.lastPasteState = this.state;
|
|
46814
47075
|
if (this.paintFormatStatus === "oneOff") {
|
|
46815
47076
|
this.paintFormatStatus = "inactive";
|
|
46816
|
-
this.status = "invisible";
|
|
46817
47077
|
}
|
|
47078
|
+
this.status = "invisible";
|
|
46818
47079
|
break;
|
|
46819
47080
|
case "COPY_PASTE_CELLS_ABOVE":
|
|
46820
47081
|
{
|
|
@@ -47041,92 +47302,6 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
47041
47302
|
}
|
|
47042
47303
|
}
|
|
47043
47304
|
|
|
47044
|
-
/**
|
|
47045
|
-
* Change the reference types inside the given token, if the token represent a range or a cell
|
|
47046
|
-
*
|
|
47047
|
-
* Eg. :
|
|
47048
|
-
* A1 => $A$1 => A$1 => $A1 => A1
|
|
47049
|
-
* A1:$B$1 => $A$1:B$1 => A$1:$B1 => $A1:B1 => A1:$B$1
|
|
47050
|
-
*/
|
|
47051
|
-
function loopThroughReferenceType(token) {
|
|
47052
|
-
if (token.type !== "REFERENCE")
|
|
47053
|
-
return token;
|
|
47054
|
-
const { xc, sheetName } = splitReference(token.value);
|
|
47055
|
-
const [left, right] = xc.split(":");
|
|
47056
|
-
const sheetRef = sheetName ? `${getCanonicalSheetName(sheetName)}!` : "";
|
|
47057
|
-
const updatedLeft = getTokenNextReferenceType(left);
|
|
47058
|
-
const updatedRight = right ? `:${getTokenNextReferenceType(right)}` : "";
|
|
47059
|
-
return { ...token, value: sheetRef + updatedLeft + updatedRight };
|
|
47060
|
-
}
|
|
47061
|
-
/**
|
|
47062
|
-
* Get a new token with a changed type of reference from the given cell token symbol.
|
|
47063
|
-
* Undefined behavior if given a token other than a cell or if the Xc contains a sheet reference
|
|
47064
|
-
*
|
|
47065
|
-
* A1 => $A$1 => A$1 => $A1 => A1
|
|
47066
|
-
*/
|
|
47067
|
-
function getTokenNextReferenceType(xc) {
|
|
47068
|
-
switch (getReferenceType(xc)) {
|
|
47069
|
-
case "none":
|
|
47070
|
-
xc = setXcToReferenceType(xc, "colrow");
|
|
47071
|
-
break;
|
|
47072
|
-
case "colrow":
|
|
47073
|
-
xc = setXcToReferenceType(xc, "row");
|
|
47074
|
-
break;
|
|
47075
|
-
case "row":
|
|
47076
|
-
xc = setXcToReferenceType(xc, "col");
|
|
47077
|
-
break;
|
|
47078
|
-
case "col":
|
|
47079
|
-
xc = setXcToReferenceType(xc, "none");
|
|
47080
|
-
break;
|
|
47081
|
-
}
|
|
47082
|
-
return xc;
|
|
47083
|
-
}
|
|
47084
|
-
/**
|
|
47085
|
-
* Returns the given XC with the given reference type.
|
|
47086
|
-
*/
|
|
47087
|
-
function setXcToReferenceType(xc, referenceType) {
|
|
47088
|
-
xc = xc.replace(/\$/g, "");
|
|
47089
|
-
let indexOfNumber;
|
|
47090
|
-
switch (referenceType) {
|
|
47091
|
-
case "col":
|
|
47092
|
-
return "$" + xc;
|
|
47093
|
-
case "row":
|
|
47094
|
-
indexOfNumber = xc.search(/[0-9]/);
|
|
47095
|
-
return xc.slice(0, indexOfNumber) + "$" + xc.slice(indexOfNumber);
|
|
47096
|
-
case "colrow":
|
|
47097
|
-
indexOfNumber = xc.search(/[0-9]/);
|
|
47098
|
-
xc = xc.slice(0, indexOfNumber) + "$" + xc.slice(indexOfNumber);
|
|
47099
|
-
return "$" + xc;
|
|
47100
|
-
case "none":
|
|
47101
|
-
return xc;
|
|
47102
|
-
}
|
|
47103
|
-
}
|
|
47104
|
-
/**
|
|
47105
|
-
* Return the type of reference used in the given XC of a cell.
|
|
47106
|
-
* Undefined behavior if the XC have a sheet reference
|
|
47107
|
-
*/
|
|
47108
|
-
function getReferenceType(xcCell) {
|
|
47109
|
-
if (isColAndRowFixed(xcCell)) {
|
|
47110
|
-
return "colrow";
|
|
47111
|
-
}
|
|
47112
|
-
else if (isColFixed(xcCell)) {
|
|
47113
|
-
return "col";
|
|
47114
|
-
}
|
|
47115
|
-
else if (isRowFixed(xcCell)) {
|
|
47116
|
-
return "row";
|
|
47117
|
-
}
|
|
47118
|
-
return "none";
|
|
47119
|
-
}
|
|
47120
|
-
function isColFixed(xc) {
|
|
47121
|
-
return xc.startsWith("$");
|
|
47122
|
-
}
|
|
47123
|
-
function isRowFixed(xc) {
|
|
47124
|
-
return xc.includes("$", 1);
|
|
47125
|
-
}
|
|
47126
|
-
function isColAndRowFixed(xc) {
|
|
47127
|
-
return xc.startsWith("$") && xc.length > 1 && xc.slice(1).includes("$");
|
|
47128
|
-
}
|
|
47129
|
-
|
|
47130
47305
|
const CELL_DELETED_MESSAGE = _t("The cell you are trying to edit has been deleted.");
|
|
47131
47306
|
class EditionPlugin extends UIPlugin {
|
|
47132
47307
|
static getters = [
|
|
@@ -47848,6 +48023,8 @@ class FilterEvaluationPlugin extends UIPlugin {
|
|
|
47848
48023
|
case "EVALUATE_CELLS":
|
|
47849
48024
|
case "ACTIVATE_SHEET":
|
|
47850
48025
|
case "REMOVE_FILTER_TABLE":
|
|
48026
|
+
case "ADD_COLUMNS_ROWS":
|
|
48027
|
+
case "REMOVE_COLUMNS_ROWS":
|
|
47851
48028
|
this.isEvaluationDirty = true;
|
|
47852
48029
|
break;
|
|
47853
48030
|
case "START":
|
|
@@ -48042,32 +48219,32 @@ const selectionStatisticFunctions = [
|
|
|
48042
48219
|
{
|
|
48043
48220
|
name: _t("Sum"),
|
|
48044
48221
|
types: [CellValueType.number],
|
|
48045
|
-
compute: (values, locale) =>
|
|
48222
|
+
compute: (values, locale) => sum([[values]], locale),
|
|
48046
48223
|
},
|
|
48047
48224
|
{
|
|
48048
48225
|
name: _t("Avg"),
|
|
48049
48226
|
types: [CellValueType.number],
|
|
48050
|
-
compute: (values, locale) =>
|
|
48227
|
+
compute: (values, locale) => average([[values]], locale),
|
|
48051
48228
|
},
|
|
48052
48229
|
{
|
|
48053
48230
|
name: _t("Min"),
|
|
48054
48231
|
types: [CellValueType.number],
|
|
48055
|
-
compute: (values, locale) =>
|
|
48232
|
+
compute: (values, locale) => min([[values]], locale),
|
|
48056
48233
|
},
|
|
48057
48234
|
{
|
|
48058
48235
|
name: _t("Max"),
|
|
48059
48236
|
types: [CellValueType.number],
|
|
48060
|
-
compute: (values, locale) =>
|
|
48237
|
+
compute: (values, locale) => max([[values]], locale),
|
|
48061
48238
|
},
|
|
48062
48239
|
{
|
|
48063
48240
|
name: _t("Count"),
|
|
48064
48241
|
types: [CellValueType.number, CellValueType.text, CellValueType.boolean, CellValueType.error],
|
|
48065
|
-
compute: (values
|
|
48242
|
+
compute: (values) => countAny([[values]]),
|
|
48066
48243
|
},
|
|
48067
48244
|
{
|
|
48068
48245
|
name: _t("Count Numbers"),
|
|
48069
48246
|
types: [CellValueType.number, CellValueType.text, CellValueType.boolean, CellValueType.error],
|
|
48070
|
-
compute: (values, locale) =>
|
|
48247
|
+
compute: (values, locale) => countNumbers([[values]], locale),
|
|
48071
48248
|
},
|
|
48072
48249
|
];
|
|
48073
48250
|
/**
|
|
@@ -51982,6 +52159,7 @@ class Spreadsheet extends Component {
|
|
|
51982
52159
|
};
|
|
51983
52160
|
sidePanel;
|
|
51984
52161
|
composer;
|
|
52162
|
+
spreadsheetRef = useRef("spreadsheet");
|
|
51985
52163
|
_focusGrid;
|
|
51986
52164
|
keyDownMapping;
|
|
51987
52165
|
isViewportTooSmall = false;
|
|
@@ -52016,6 +52194,18 @@ class Spreadsheet extends Component {
|
|
|
52016
52194
|
clipboard: this.env.clipboard || instantiateClipboard(),
|
|
52017
52195
|
startCellEdition: (content) => this.onGridComposerCellFocused(content),
|
|
52018
52196
|
});
|
|
52197
|
+
useEffect(() => {
|
|
52198
|
+
/**
|
|
52199
|
+
* Only refocus the grid if the active element is not a child of the spreadsheet
|
|
52200
|
+
* (i.e. activeElement is outside of the spreadsheetRef component)
|
|
52201
|
+
* and spreadsheet is a child of that element. Anything else means that the focus
|
|
52202
|
+
* is on an element that needs to keep it.
|
|
52203
|
+
*/
|
|
52204
|
+
if (!this.spreadsheetRef.el.contains(document.activeElement) &&
|
|
52205
|
+
document.activeElement?.contains(this.spreadsheetRef.el)) {
|
|
52206
|
+
this.focusGrid();
|
|
52207
|
+
}
|
|
52208
|
+
}, () => [this.env.model.getters.getActiveSheetId()]);
|
|
52019
52209
|
useExternalListener(window, "resize", () => this.render(true));
|
|
52020
52210
|
useExternalListener(window, "beforeunload", this.unbindModelEvents.bind(this));
|
|
52021
52211
|
this.bindModelEvents();
|
|
@@ -52097,7 +52287,7 @@ class Spreadsheet extends Component {
|
|
|
52097
52287
|
}
|
|
52098
52288
|
focusGrid() {
|
|
52099
52289
|
if (!this._focusGrid) {
|
|
52100
|
-
|
|
52290
|
+
return;
|
|
52101
52291
|
}
|
|
52102
52292
|
this._focusGrid();
|
|
52103
52293
|
}
|
|
@@ -53366,7 +53556,7 @@ class SelectionStreamProcessorImpl {
|
|
|
53366
53556
|
scrollIntoView: false,
|
|
53367
53557
|
});
|
|
53368
53558
|
}
|
|
53369
|
-
const tableZone = this.
|
|
53559
|
+
const tableZone = this.getters.getContiguousZone(sheetId, anchor.zone);
|
|
53370
53560
|
return !deepEquals(tableZone, anchor.zone)
|
|
53371
53561
|
? this.modifyAnchor({ ...anchor, zone: tableZone }, "updateAnchor", {
|
|
53372
53562
|
scrollIntoView: false,
|
|
@@ -53379,7 +53569,8 @@ class SelectionStreamProcessorImpl {
|
|
|
53379
53569
|
* cells bordering it
|
|
53380
53570
|
*/
|
|
53381
53571
|
selectTableAroundSelection() {
|
|
53382
|
-
const
|
|
53572
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
53573
|
+
const tableZone = this.getters.getContiguousZone(sheetId, this.anchor.zone);
|
|
53383
53574
|
return this.modifyAnchor({ ...this.anchor, zone: tableZone }, "updateAnchor", {
|
|
53384
53575
|
scrollIntoView: false,
|
|
53385
53576
|
});
|
|
@@ -53556,11 +53747,12 @@ class SelectionStreamProcessorImpl {
|
|
|
53556
53747
|
* next cluster if the given cell is outside a cluster or at the border of a cluster in the given direction.
|
|
53557
53748
|
*/
|
|
53558
53749
|
getEndOfCluster(startPosition, dim, dir) {
|
|
53559
|
-
const
|
|
53750
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
53560
53751
|
let currentPosition = startPosition;
|
|
53561
53752
|
// If both the current cell and the next cell are not empty, we want to go to the end of the cluster
|
|
53562
53753
|
const nextCellPosition = this.getNextCellPosition(startPosition, dim, dir);
|
|
53563
|
-
let mode = !this.isCellEmpty(currentPosition,
|
|
53754
|
+
let mode = !this.getters.isCellEmpty({ ...currentPosition, sheetId }) &&
|
|
53755
|
+
!this.getters.isCellEmpty({ ...nextCellPosition, sheetId })
|
|
53564
53756
|
? "endOfCluster"
|
|
53565
53757
|
: "nextCluster";
|
|
53566
53758
|
while (true) {
|
|
@@ -53570,7 +53762,7 @@ class SelectionStreamProcessorImpl {
|
|
|
53570
53762
|
currentPosition.row === nextCellPosition.row) {
|
|
53571
53763
|
break;
|
|
53572
53764
|
}
|
|
53573
|
-
const isNextCellEmpty = this.isCellEmpty(nextCellPosition,
|
|
53765
|
+
const isNextCellEmpty = this.getters.isCellEmpty({ ...nextCellPosition, sheetId });
|
|
53574
53766
|
if (mode === "endOfCluster" && isNextCellEmpty) {
|
|
53575
53767
|
break;
|
|
53576
53768
|
}
|
|
@@ -53583,15 +53775,6 @@ class SelectionStreamProcessorImpl {
|
|
|
53583
53775
|
}
|
|
53584
53776
|
return dim === "cols" ? currentPosition.col : currentPosition.row;
|
|
53585
53777
|
}
|
|
53586
|
-
/**
|
|
53587
|
-
* Check if a cell is empty or undefined in the model. If the cell is part of a merge,
|
|
53588
|
-
* check if the merge containing the cell is empty.
|
|
53589
|
-
*/
|
|
53590
|
-
isCellEmpty({ col, row }, sheetId = this.getters.getActiveSheetId()) {
|
|
53591
|
-
const position = this.getters.getMainCellPosition({ sheetId, col, row });
|
|
53592
|
-
const cell = this.getters.getEvaluatedCell(position);
|
|
53593
|
-
return cell.type === CellValueType.empty;
|
|
53594
|
-
}
|
|
53595
53778
|
/** Computes the next cell position in the given direction by crossing through merges and skipping hidden cells.
|
|
53596
53779
|
*
|
|
53597
53780
|
* This has the same behaviour as getNextAvailablePosition() for certain arguments, but use this method instead
|
|
@@ -53610,45 +53793,6 @@ class SelectionStreamProcessorImpl {
|
|
|
53610
53793
|
getPosition() {
|
|
53611
53794
|
return { ...this.anchor.cell };
|
|
53612
53795
|
}
|
|
53613
|
-
/**
|
|
53614
|
-
* Expand the given zone to a table.
|
|
53615
|
-
* We define a table by the smallest zone that contain the anchor and that have only empty
|
|
53616
|
-
* cells bordering it
|
|
53617
|
-
*/
|
|
53618
|
-
expandZoneToTable(zoneToExpand) {
|
|
53619
|
-
/** Try to expand the zone by one col/row in any direction to include a new non-empty cell */
|
|
53620
|
-
const expandZone = (zone) => {
|
|
53621
|
-
for (const col of range(zone.left, zone.right + 1)) {
|
|
53622
|
-
if (!this.isCellEmpty({ col, row: zone.top - 1 })) {
|
|
53623
|
-
return { ...zone, top: zone.top - 1 };
|
|
53624
|
-
}
|
|
53625
|
-
if (!this.isCellEmpty({ col, row: zone.bottom + 1 })) {
|
|
53626
|
-
return { ...zone, bottom: zone.bottom + 1 };
|
|
53627
|
-
}
|
|
53628
|
-
}
|
|
53629
|
-
for (const row of range(zone.top, zone.bottom + 1)) {
|
|
53630
|
-
if (!this.isCellEmpty({ col: zone.left - 1, row })) {
|
|
53631
|
-
return { ...zone, left: zone.left - 1 };
|
|
53632
|
-
}
|
|
53633
|
-
if (!this.isCellEmpty({ col: zone.right + 1, row })) {
|
|
53634
|
-
return { ...zone, right: zone.right + 1 };
|
|
53635
|
-
}
|
|
53636
|
-
}
|
|
53637
|
-
return zone;
|
|
53638
|
-
};
|
|
53639
|
-
let hasExpanded = false;
|
|
53640
|
-
let zone = zoneToExpand;
|
|
53641
|
-
do {
|
|
53642
|
-
hasExpanded = false;
|
|
53643
|
-
const newZone = expandZone(zone);
|
|
53644
|
-
if (!isEqual(zone, newZone)) {
|
|
53645
|
-
hasExpanded = true;
|
|
53646
|
-
zone = newZone;
|
|
53647
|
-
continue;
|
|
53648
|
-
}
|
|
53649
|
-
} while (hasExpanded);
|
|
53650
|
-
return zone;
|
|
53651
|
-
}
|
|
53652
53796
|
}
|
|
53653
53797
|
|
|
53654
53798
|
class StateObserver {
|
|
@@ -55536,19 +55680,22 @@ class Model extends EventBus {
|
|
|
55536
55680
|
* Check if the given command is allowed by all the plugins and the history.
|
|
55537
55681
|
*/
|
|
55538
55682
|
checkDispatchAllowed(command) {
|
|
55539
|
-
|
|
55540
|
-
|
|
55683
|
+
const results = isCoreCommand(command)
|
|
55684
|
+
? this.checkDispatchAllowedCoreCommand(command)
|
|
55685
|
+
: this.checkDispatchAllowedLocalCommand(command);
|
|
55686
|
+
if (results.some((r) => r !== "Success" /* CommandResult.Success */)) {
|
|
55687
|
+
return new DispatchResult(results.flat());
|
|
55541
55688
|
}
|
|
55542
|
-
return
|
|
55689
|
+
return DispatchResult.Success;
|
|
55543
55690
|
}
|
|
55544
55691
|
checkDispatchAllowedCoreCommand(command) {
|
|
55545
55692
|
const results = this.corePlugins.map((handler) => handler.allowDispatch(command));
|
|
55546
55693
|
results.push(this.range.allowDispatch(command));
|
|
55547
|
-
return
|
|
55694
|
+
return results;
|
|
55548
55695
|
}
|
|
55549
55696
|
checkDispatchAllowedLocalCommand(command) {
|
|
55550
55697
|
const results = this.uiHandlers.map((handler) => handler.allowDispatch(command));
|
|
55551
|
-
return
|
|
55698
|
+
return results;
|
|
55552
55699
|
}
|
|
55553
55700
|
finalize() {
|
|
55554
55701
|
this.status = 3 /* Status.Finalizing */;
|
|
@@ -55843,6 +55990,7 @@ const components = {
|
|
|
55843
55990
|
FigureComponent,
|
|
55844
55991
|
Menu,
|
|
55845
55992
|
SelectionInput,
|
|
55993
|
+
ValidationMessages,
|
|
55846
55994
|
};
|
|
55847
55995
|
const hooks = {
|
|
55848
55996
|
useDragAndDropListItems,
|
|
@@ -55857,9 +56005,9 @@ const constants = {
|
|
|
55857
56005
|
DEFAULT_LOCALE,
|
|
55858
56006
|
};
|
|
55859
56007
|
|
|
55860
|
-
export { AbstractChart, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, compile, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, tokenize };
|
|
56008
|
+
export { AbstractChart, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, tokenize };
|
|
55861
56009
|
|
|
55862
56010
|
|
|
55863
|
-
__info__.version = "17.1.0-alpha.
|
|
55864
|
-
__info__.date = "2023-11-
|
|
55865
|
-
__info__.hash = "
|
|
56011
|
+
__info__.version = "17.1.0-alpha.4";
|
|
56012
|
+
__info__.date = "2023-11-24T13:12:24.882Z";
|
|
56013
|
+
__info__.hash = "255821b";
|