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