@odoo/o-spreadsheet 17.1.3 → 17.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/o-spreadsheet.cjs.js +320 -196
- package/dist/o-spreadsheet.d.ts +47 -22
- package/dist/o-spreadsheet.esm.js +320 -196
- package/dist/o-spreadsheet.iife.js +320 -196
- package/dist/o-spreadsheet.iife.min.js +262 -261
- package/dist/o_spreadsheet.xml +19 -36
- 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.
|
|
6
|
-
* @date 2024-02-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 17.1.5
|
|
6
|
+
* @date 2024-02-16T14:23:54.651Z
|
|
7
|
+
* @hash 29d8ad6
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { Component, useRef, onMounted, useEffect, onWillPatch, useState, onWillUpdateProps, onPatched, useComponent, useExternalListener, onWillUnmount, onWillStart, xml, useChildSubEnv, useSubEnv, markRaw } from '@odoo/owl';
|
|
@@ -451,8 +451,8 @@ function isObjectEmptyRecursive(argument) {
|
|
|
451
451
|
* If the given item does not exist in the dictionary, it creates one with a new id.
|
|
452
452
|
*/
|
|
453
453
|
function getItemId(item, itemsDic) {
|
|
454
|
-
for (
|
|
455
|
-
if (deepEquals(
|
|
454
|
+
for (const key in itemsDic) {
|
|
455
|
+
if (deepEquals(itemsDic[key], item)) {
|
|
456
456
|
return parseInt(key, 10);
|
|
457
457
|
}
|
|
458
458
|
}
|
|
@@ -551,11 +551,13 @@ function deepEquals(o1, o2) {
|
|
|
551
551
|
if (typeof o1 !== "object")
|
|
552
552
|
return o1 === o2;
|
|
553
553
|
// Objects can have different keys if the values are undefined
|
|
554
|
-
const
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
554
|
+
for (const key in o2) {
|
|
555
|
+
if (!(key in o1) && o2[key] !== undefined) {
|
|
556
|
+
return false;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
for (const key in o1) {
|
|
560
|
+
if (typeof o1[key] !== typeof o2[key])
|
|
559
561
|
return false;
|
|
560
562
|
if (typeof o1[key] === "object") {
|
|
561
563
|
if (!deepEquals(o1[key], o2[key]))
|
|
@@ -625,18 +627,18 @@ function isConsecutive(iterable) {
|
|
|
625
627
|
return true;
|
|
626
628
|
}
|
|
627
629
|
class JetSet extends Set {
|
|
628
|
-
|
|
630
|
+
addMany(iterable) {
|
|
629
631
|
for (const element of iterable) {
|
|
630
632
|
super.add(element);
|
|
631
633
|
}
|
|
632
634
|
return this;
|
|
633
635
|
}
|
|
634
|
-
|
|
635
|
-
let
|
|
636
|
+
deleteMany(iterable) {
|
|
637
|
+
let wasDeleted = false;
|
|
636
638
|
for (const element of iterable) {
|
|
637
|
-
|
|
639
|
+
wasDeleted ||= super.delete(element);
|
|
638
640
|
}
|
|
639
|
-
return
|
|
641
|
+
return wasDeleted;
|
|
640
642
|
}
|
|
641
643
|
}
|
|
642
644
|
/**
|
|
@@ -1934,7 +1936,7 @@ class DispatchResult {
|
|
|
1934
1936
|
* Static helper which returns a successful DispatchResult
|
|
1935
1937
|
*/
|
|
1936
1938
|
static get Success() {
|
|
1937
|
-
return
|
|
1939
|
+
return SUCCESS;
|
|
1938
1940
|
}
|
|
1939
1941
|
get isSuccessful() {
|
|
1940
1942
|
return this.reasons.length === 0;
|
|
@@ -1947,6 +1949,7 @@ class DispatchResult {
|
|
|
1947
1949
|
return this.reasons.includes(reason);
|
|
1948
1950
|
}
|
|
1949
1951
|
}
|
|
1952
|
+
const SUCCESS = new DispatchResult();
|
|
1950
1953
|
var CommandResult;
|
|
1951
1954
|
(function (CommandResult) {
|
|
1952
1955
|
CommandResult["Success"] = "Success";
|
|
@@ -2938,6 +2941,9 @@ function formatValue(value, { format, locale }) {
|
|
|
2938
2941
|
}
|
|
2939
2942
|
switch (typeof value) {
|
|
2940
2943
|
case "string":
|
|
2944
|
+
if (value.includes('\\"')) {
|
|
2945
|
+
return value.replace(/\\"/g, '"');
|
|
2946
|
+
}
|
|
2941
2947
|
return value;
|
|
2942
2948
|
case "boolean":
|
|
2943
2949
|
return value ? "TRUE" : "FALSE";
|
|
@@ -4991,14 +4997,8 @@ function createDataSets(getters, dataSetsString, sheetId, dataSetsHaveTitle) {
|
|
|
4991
4997
|
: undefined));
|
|
4992
4998
|
}
|
|
4993
4999
|
}
|
|
4994
|
-
else if (zone.left === zone.right && zone.top === zone.bottom) {
|
|
4995
|
-
// A single cell. If it's only the title, the dataset is not added.
|
|
4996
|
-
if (!dataSetsHaveTitle) {
|
|
4997
|
-
dataSets.push(createDataSet(getters, dataSetSheetId, zone, undefined));
|
|
4998
|
-
}
|
|
4999
|
-
}
|
|
5000
5000
|
else {
|
|
5001
|
-
/* 1 row or 1 column */
|
|
5001
|
+
/* 1 cell, 1 row or 1 column */
|
|
5002
5002
|
dataSets.push(createDataSet(getters, dataSetSheetId, zone, dataSetsHaveTitle
|
|
5003
5003
|
? {
|
|
5004
5004
|
top: zone.top,
|
|
@@ -7441,7 +7441,7 @@ function tokenize(str, locale = DEFAULT_LOCALE) {
|
|
|
7441
7441
|
while (!chars.isOver()) {
|
|
7442
7442
|
let token = tokenizeSpace(chars) ||
|
|
7443
7443
|
tokenizeArgsSeparator(chars, locale) ||
|
|
7444
|
-
|
|
7444
|
+
tokenizeParenthesis(chars) ||
|
|
7445
7445
|
tokenizeOperator(chars) ||
|
|
7446
7446
|
tokenizeString(chars) ||
|
|
7447
7447
|
tokenizeDebugger(chars) ||
|
|
@@ -7462,15 +7462,14 @@ function tokenizeDebugger(chars) {
|
|
|
7462
7462
|
}
|
|
7463
7463
|
return null;
|
|
7464
7464
|
}
|
|
7465
|
-
const
|
|
7466
|
-
"(": "LEFT_PAREN",
|
|
7467
|
-
")": "RIGHT_PAREN",
|
|
7465
|
+
const parenthesis = {
|
|
7466
|
+
"(": { type: "LEFT_PAREN", value: "(" },
|
|
7467
|
+
")": { type: "RIGHT_PAREN", value: ")" },
|
|
7468
7468
|
};
|
|
7469
|
-
function
|
|
7470
|
-
if (chars.current
|
|
7469
|
+
function tokenizeParenthesis(chars) {
|
|
7470
|
+
if (chars.current === "(" || chars.current === ")") {
|
|
7471
7471
|
const value = chars.shift();
|
|
7472
|
-
|
|
7473
|
-
return { type, value };
|
|
7472
|
+
return parenthesis[value];
|
|
7474
7473
|
}
|
|
7475
7474
|
return null;
|
|
7476
7475
|
}
|
|
@@ -7491,7 +7490,12 @@ function tokenizeOperator(chars) {
|
|
|
7491
7490
|
}
|
|
7492
7491
|
return null;
|
|
7493
7492
|
}
|
|
7493
|
+
const FIRST_POSSIBLE_NUMBER_CHARS = new Set("0123456789");
|
|
7494
7494
|
function tokenizeNumber(chars, locale) {
|
|
7495
|
+
if (!FIRST_POSSIBLE_NUMBER_CHARS.has(chars.current) &&
|
|
7496
|
+
chars.current !== locale.decimalSeparator) {
|
|
7497
|
+
return null;
|
|
7498
|
+
}
|
|
7495
7499
|
const match = chars.remaining().match(getFormulaNumberRegex(locale.decimalSeparator));
|
|
7496
7500
|
if (match) {
|
|
7497
7501
|
chars.advanceBy(match[0].length);
|
|
@@ -7516,7 +7520,7 @@ function tokenizeString(chars) {
|
|
|
7516
7520
|
}
|
|
7517
7521
|
return null;
|
|
7518
7522
|
}
|
|
7519
|
-
const separatorRegexp =
|
|
7523
|
+
const separatorRegexp = /^[\w\.!\$]+/;
|
|
7520
7524
|
/**
|
|
7521
7525
|
* A "Symbol" is just basically any word-like element that can appear in a
|
|
7522
7526
|
* formula, which is not a string. So:
|
|
@@ -7556,8 +7560,11 @@ function tokenizeSymbol(chars) {
|
|
|
7556
7560
|
};
|
|
7557
7561
|
}
|
|
7558
7562
|
}
|
|
7559
|
-
|
|
7560
|
-
|
|
7563
|
+
const match = chars.remaining().match(separatorRegexp);
|
|
7564
|
+
if (match) {
|
|
7565
|
+
const value = match[0];
|
|
7566
|
+
result += value;
|
|
7567
|
+
chars.advanceBy(value.length);
|
|
7561
7568
|
}
|
|
7562
7569
|
if (result.length) {
|
|
7563
7570
|
const value = result;
|
|
@@ -7619,7 +7626,10 @@ class TokenizingChars {
|
|
|
7619
7626
|
return this.text.substring(this.currentIndex);
|
|
7620
7627
|
}
|
|
7621
7628
|
currentStartsWith(str) {
|
|
7622
|
-
|
|
7629
|
+
if (this.current !== str[0]) {
|
|
7630
|
+
return false;
|
|
7631
|
+
}
|
|
7632
|
+
for (let j = 1; j < str.length; j++) {
|
|
7623
7633
|
if (this.text[this.currentIndex + j] !== str[j]) {
|
|
7624
7634
|
return false;
|
|
7625
7635
|
}
|
|
@@ -7646,6 +7656,9 @@ function isValidLocale(locale) {
|
|
|
7646
7656
|
if (locale.formulaArgSeparator === locale.decimalSeparator) {
|
|
7647
7657
|
return false;
|
|
7648
7658
|
}
|
|
7659
|
+
if (locale.thousandsSeparator === locale.decimalSeparator) {
|
|
7660
|
+
return false;
|
|
7661
|
+
}
|
|
7649
7662
|
try {
|
|
7650
7663
|
formatValue(1, { locale, format: "#,##0.00" });
|
|
7651
7664
|
formatValue(1, { locale, format: locale.dateFormat });
|
|
@@ -7736,7 +7749,7 @@ function canonicalizeNumberLiteral(content, locale) {
|
|
|
7736
7749
|
if (locale.decimalSeparator === "." || !isNumber(content, locale)) {
|
|
7737
7750
|
return content;
|
|
7738
7751
|
}
|
|
7739
|
-
return content.replace(locale.decimalSeparator, ".");
|
|
7752
|
+
return content.replace(locale.thousandsSeparator, "").replace(locale.decimalSeparator, ".");
|
|
7740
7753
|
}
|
|
7741
7754
|
/**
|
|
7742
7755
|
* Change a content string from the given locale to its canonical form (en_US locale). Also convert date string.
|
|
@@ -8651,7 +8664,7 @@ class BarChart extends AbstractChart {
|
|
|
8651
8664
|
return undefined;
|
|
8652
8665
|
const dataSets = this.dataSets
|
|
8653
8666
|
.map((ds) => toExcelDataset(this.getters, ds))
|
|
8654
|
-
.filter((ds) => ds.range !== ""
|
|
8667
|
+
.filter((ds) => ds.range !== "" && ds.range !== CellErrorType.InvalidReference);
|
|
8655
8668
|
const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
8656
8669
|
return {
|
|
8657
8670
|
...this.getDefinition(),
|
|
@@ -9229,7 +9242,7 @@ class LineChart extends AbstractChart {
|
|
|
9229
9242
|
return undefined;
|
|
9230
9243
|
const dataSets = this.dataSets
|
|
9231
9244
|
.map((ds) => toExcelDataset(this.getters, ds))
|
|
9232
|
-
.filter((ds) => ds.range !== ""
|
|
9245
|
+
.filter((ds) => ds.range !== "" && ds.range !== CellErrorType.InvalidReference);
|
|
9233
9246
|
const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
9234
9247
|
return {
|
|
9235
9248
|
...this.getDefinition(),
|
|
@@ -9535,7 +9548,7 @@ class PieChart extends AbstractChart {
|
|
|
9535
9548
|
return undefined;
|
|
9536
9549
|
const dataSets = this.dataSets
|
|
9537
9550
|
.map((ds) => toExcelDataset(this.getters, ds))
|
|
9538
|
-
.filter((ds) => ds.range !== ""
|
|
9551
|
+
.filter((ds) => ds.range !== "" && ds.range !== CellErrorType.InvalidReference);
|
|
9539
9552
|
const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
9540
9553
|
return {
|
|
9541
9554
|
...this.getDefinition(),
|
|
@@ -10831,6 +10844,12 @@ const INSERT_LINK = (env) => {
|
|
|
10831
10844
|
let { col, row } = env.model.getters.getActivePosition();
|
|
10832
10845
|
env.model.dispatch("OPEN_CELL_POPOVER", { col, row, popoverType: "LinkEditor" });
|
|
10833
10846
|
};
|
|
10847
|
+
const INSERT_LINK_NAME = (env) => {
|
|
10848
|
+
const sheetId = env.model.getters.getActiveSheetId();
|
|
10849
|
+
const { col, row } = env.model.getters.getActivePosition();
|
|
10850
|
+
const cell = env.model.getters.getEvaluatedCell({ sheetId, col, row });
|
|
10851
|
+
return cell && cell.link ? _t("Edit link") : _t("Insert link");
|
|
10852
|
+
};
|
|
10834
10853
|
//------------------------------------------------------------------------------
|
|
10835
10854
|
// Filters action
|
|
10836
10855
|
//------------------------------------------------------------------------------
|
|
@@ -18682,6 +18701,9 @@ const HLOOKUP = {
|
|
|
18682
18701
|
compute: function (searchKey, range, index, isSorted = { value: DEFAULT_IS_SORTED }) {
|
|
18683
18702
|
const _index = Math.trunc(toNumber(index?.value, this.locale));
|
|
18684
18703
|
assert(() => 1 <= _index && _index <= range[0].length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
|
|
18704
|
+
if (searchKey && isEvaluationError(searchKey.value)) {
|
|
18705
|
+
return searchKey;
|
|
18706
|
+
}
|
|
18685
18707
|
const getValueFromRange = (range, index) => range[index][0].value;
|
|
18686
18708
|
const _isSorted = toBoolean(isSorted.value);
|
|
18687
18709
|
const colIndex = _isSorted
|
|
@@ -18849,6 +18871,9 @@ const VLOOKUP = {
|
|
|
18849
18871
|
compute: function (searchKey, range, index, isSorted = { value: DEFAULT_IS_SORTED }) {
|
|
18850
18872
|
const _index = Math.trunc(toNumber(index?.value, this.locale));
|
|
18851
18873
|
assert(() => 1 <= _index && _index <= range.length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
|
|
18874
|
+
if (searchKey && isEvaluationError(searchKey.value)) {
|
|
18875
|
+
return searchKey;
|
|
18876
|
+
}
|
|
18852
18877
|
const getValueFromRange = (range, index) => range[0][index].value;
|
|
18853
18878
|
const _isSorted = toBoolean(isSorted.value);
|
|
18854
18879
|
const rowIndex = _isSorted
|
|
@@ -18888,6 +18913,9 @@ const XLOOKUP = {
|
|
|
18888
18913
|
assert(() => lookupDirection === "col"
|
|
18889
18914
|
? returnRange[0].length === lookupRange[0].length
|
|
18890
18915
|
: returnRange.length === lookupRange.length, _t("return_range should have the same dimensions as lookup_range."));
|
|
18916
|
+
if (searchKey && isEvaluationError(searchKey.value)) {
|
|
18917
|
+
return [[searchKey]];
|
|
18918
|
+
}
|
|
18891
18919
|
const getElement = lookupDirection === "col"
|
|
18892
18920
|
? (range, index) => range[0][index].value
|
|
18893
18921
|
: (range, index) => range[index][0].value;
|
|
@@ -20066,7 +20094,7 @@ cellMenuRegistry
|
|
|
20066
20094
|
})
|
|
20067
20095
|
.add("insert_link", {
|
|
20068
20096
|
...insertLink,
|
|
20069
|
-
name:
|
|
20097
|
+
name: INSERT_LINK_NAME,
|
|
20070
20098
|
sequence: 150,
|
|
20071
20099
|
separator: true,
|
|
20072
20100
|
});
|
|
@@ -26509,6 +26537,17 @@ class TextValueProvider extends Component {
|
|
|
26509
26537
|
onValueSelected: Function,
|
|
26510
26538
|
onValueHovered: Function,
|
|
26511
26539
|
};
|
|
26540
|
+
autoCompleteListRef = useRef("autoCompleteList");
|
|
26541
|
+
setup() {
|
|
26542
|
+
useEffect(() => {
|
|
26543
|
+
const selectedIndex = this.props.selectedIndex;
|
|
26544
|
+
if (selectedIndex === undefined) {
|
|
26545
|
+
return;
|
|
26546
|
+
}
|
|
26547
|
+
const selectedElement = this.autoCompleteListRef.el?.children[selectedIndex];
|
|
26548
|
+
selectedElement?.scrollIntoView?.({ block: "nearest" });
|
|
26549
|
+
}, () => [this.props.selectedIndex, this.autoCompleteListRef.el]);
|
|
26550
|
+
}
|
|
26512
26551
|
}
|
|
26513
26552
|
|
|
26514
26553
|
class ContentEditableHelper {
|
|
@@ -26953,6 +26992,7 @@ css /* scss */ `
|
|
|
26953
26992
|
position: absolute;
|
|
26954
26993
|
margin: 1px 4px;
|
|
26955
26994
|
pointer-events: none;
|
|
26995
|
+
overflow: auto;
|
|
26956
26996
|
|
|
26957
26997
|
.o-semi-bold {
|
|
26958
26998
|
/** FIXME: to remove in favor of Bootstrap
|
|
@@ -26969,15 +27009,17 @@ class Composer extends Component {
|
|
|
26969
27009
|
focus: {
|
|
26970
27010
|
validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value),
|
|
26971
27011
|
},
|
|
26972
|
-
onComposerContentFocused: Function,
|
|
26973
27012
|
inputStyle: { type: String, optional: true },
|
|
26974
27013
|
rect: { type: Object, optional: true },
|
|
26975
27014
|
delimitation: { type: Object, optional: true },
|
|
26976
|
-
|
|
27015
|
+
onComposerCellFocused: { type: Function, optional: true },
|
|
27016
|
+
onComposerContentFocused: Function,
|
|
27017
|
+
isDefaultFocus: { type: Boolean, optional: true },
|
|
26977
27018
|
};
|
|
26978
27019
|
static components = { TextValueProvider, FunctionDescriptionProvider };
|
|
26979
27020
|
static defaultProps = {
|
|
26980
27021
|
inputStyle: "",
|
|
27022
|
+
isDefaultFocus: false,
|
|
26981
27023
|
};
|
|
26982
27024
|
composerRef = useRef("o_composer");
|
|
26983
27025
|
contentHelper = new ContentEditableHelper(this.composerRef.el);
|
|
@@ -27008,7 +27050,10 @@ class Composer extends Component {
|
|
|
27008
27050
|
if (this.props.delimitation && this.props.rect) {
|
|
27009
27051
|
const { x: cellX, y: cellY, height: cellHeight } = this.props.rect;
|
|
27010
27052
|
const remainingHeight = this.props.delimitation.height - (cellY + cellHeight);
|
|
27053
|
+
assistantStyle["max-height"] = `${remainingHeight}px`;
|
|
27011
27054
|
if (cellY > remainingHeight) {
|
|
27055
|
+
const availableSpaceAbove = cellY;
|
|
27056
|
+
assistantStyle["max-height"] = `${availableSpaceAbove}px`;
|
|
27012
27057
|
// render top
|
|
27013
27058
|
// We compensate 2 px of margin on the assistant style + 1px for design reasons
|
|
27014
27059
|
assistantStyle.top = `-3px`;
|
|
@@ -27034,7 +27079,6 @@ class Composer extends Component {
|
|
|
27034
27079
|
F4: this.processF4Key,
|
|
27035
27080
|
Tab: (ev) => this.processTabKey(ev, "right"),
|
|
27036
27081
|
"Shift+Tab": (ev) => this.processTabKey(ev, "left"),
|
|
27037
|
-
"Ctrl+ ": this.processSpaceKey,
|
|
27038
27082
|
};
|
|
27039
27083
|
keyCodeMapping = {
|
|
27040
27084
|
NumpadDecimal: this.processNumpadDecimal,
|
|
@@ -27042,12 +27086,12 @@ class Composer extends Component {
|
|
|
27042
27086
|
setup() {
|
|
27043
27087
|
onMounted(() => {
|
|
27044
27088
|
const el = this.composerRef.el;
|
|
27089
|
+
if (this.props.isDefaultFocus) {
|
|
27090
|
+
this.env.focusableElement.setFocusableElement(el);
|
|
27091
|
+
}
|
|
27045
27092
|
this.contentHelper.updateEl(el);
|
|
27046
27093
|
this.processTokenAtCursor();
|
|
27047
27094
|
});
|
|
27048
|
-
onWillUnmount(() => {
|
|
27049
|
-
this.props.onComposerUnmounted?.();
|
|
27050
|
-
});
|
|
27051
27095
|
useEffect(() => {
|
|
27052
27096
|
this.processContent();
|
|
27053
27097
|
});
|
|
@@ -27056,7 +27100,8 @@ class Composer extends Component {
|
|
|
27056
27100
|
// Handlers
|
|
27057
27101
|
// ---------------------------------------------------------------------------
|
|
27058
27102
|
processArrowKeys(ev) {
|
|
27059
|
-
if (this.env.model.getters.isSelectingForComposer()
|
|
27103
|
+
if (this.env.model.getters.isSelectingForComposer() ||
|
|
27104
|
+
this.env.model.getters.getEditionMode() === "inactive") {
|
|
27060
27105
|
this.functionDescriptionState.showDescription = false;
|
|
27061
27106
|
// Prevent the default content editable behavior which moves the cursor
|
|
27062
27107
|
ev.preventDefault();
|
|
@@ -27099,23 +27144,19 @@ class Composer extends Component {
|
|
|
27099
27144
|
processTabKey(ev, direction) {
|
|
27100
27145
|
ev.preventDefault();
|
|
27101
27146
|
ev.stopPropagation();
|
|
27102
|
-
|
|
27103
|
-
|
|
27104
|
-
|
|
27105
|
-
|
|
27106
|
-
|
|
27107
|
-
|
|
27147
|
+
if (this.env.model.getters.getEditionMode() !== "inactive") {
|
|
27148
|
+
const state = this.autoCompleteState;
|
|
27149
|
+
if (state.showProvider && state.selectedIndex !== undefined) {
|
|
27150
|
+
const autoCompleteValue = this.autoCompleteState.values[state.selectedIndex]?.text;
|
|
27151
|
+
if (autoCompleteValue) {
|
|
27152
|
+
this.autoComplete(autoCompleteValue);
|
|
27153
|
+
return;
|
|
27154
|
+
}
|
|
27108
27155
|
}
|
|
27156
|
+
interactiveStopEdition(this.env);
|
|
27109
27157
|
}
|
|
27110
|
-
interactiveStopEdition(this.env);
|
|
27111
27158
|
this.env.model.selection.moveAnchorCell(direction, 1);
|
|
27112
27159
|
}
|
|
27113
|
-
processSpaceKey(ev) {
|
|
27114
|
-
ev.preventDefault();
|
|
27115
|
-
ev.stopPropagation();
|
|
27116
|
-
this.showFunctionAutocomplete("");
|
|
27117
|
-
this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
|
|
27118
|
-
}
|
|
27119
27160
|
processEnterKey(ev, direction) {
|
|
27120
27161
|
ev.preventDefault();
|
|
27121
27162
|
ev.stopPropagation();
|
|
@@ -27177,6 +27218,9 @@ class Composer extends Component {
|
|
|
27177
27218
|
this.compositionActive = false;
|
|
27178
27219
|
}
|
|
27179
27220
|
onKeydown(ev) {
|
|
27221
|
+
if (this.env.model.getters.getEditionMode() === "inactive") {
|
|
27222
|
+
return;
|
|
27223
|
+
}
|
|
27180
27224
|
if (ev.key.startsWith("Arrow")) {
|
|
27181
27225
|
this.processArrowKeys(ev);
|
|
27182
27226
|
return;
|
|
@@ -27190,14 +27234,33 @@ class Composer extends Component {
|
|
|
27190
27234
|
ev.stopPropagation();
|
|
27191
27235
|
}
|
|
27192
27236
|
}
|
|
27237
|
+
onPaste(ev) {
|
|
27238
|
+
if (this.env.model.getters.getEditionMode() !== "inactive") {
|
|
27239
|
+
ev.stopPropagation();
|
|
27240
|
+
}
|
|
27241
|
+
}
|
|
27193
27242
|
/*
|
|
27194
27243
|
* Triggered automatically by the content-editable between the keydown and key up
|
|
27195
27244
|
* */
|
|
27196
27245
|
onInput(ev) {
|
|
27197
|
-
if (
|
|
27246
|
+
if (!this.shouldProcessInputEvents) {
|
|
27198
27247
|
return;
|
|
27199
27248
|
}
|
|
27200
|
-
|
|
27249
|
+
if (ev.inputType === "insertFromPaste" &&
|
|
27250
|
+
this.env.model.getters.getEditionMode() === "inactive") {
|
|
27251
|
+
return;
|
|
27252
|
+
}
|
|
27253
|
+
ev.stopPropagation();
|
|
27254
|
+
let content;
|
|
27255
|
+
if (this.env.model.getters.getEditionMode() === "inactive") {
|
|
27256
|
+
content = ev.data || "";
|
|
27257
|
+
}
|
|
27258
|
+
else {
|
|
27259
|
+
content = this.contentHelper.getText();
|
|
27260
|
+
}
|
|
27261
|
+
if (this.props.focus === "inactive") {
|
|
27262
|
+
return this.props.onComposerCellFocused?.(content);
|
|
27263
|
+
}
|
|
27201
27264
|
let selection = this.contentHelper.getCurrentSelection();
|
|
27202
27265
|
this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
|
|
27203
27266
|
this.env.model.dispatch("SET_CURRENT_CONTENT", {
|
|
@@ -27273,9 +27336,8 @@ class Composer extends Component {
|
|
|
27273
27336
|
}
|
|
27274
27337
|
const newSelection = this.contentHelper.getCurrentSelection();
|
|
27275
27338
|
this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
|
|
27276
|
-
|
|
27277
|
-
|
|
27278
|
-
}
|
|
27339
|
+
this.props.onComposerContentFocused();
|
|
27340
|
+
if (this.props.focus === "inactive") ;
|
|
27279
27341
|
this.env.model.dispatch("CHANGE_COMPOSER_CURSOR_SELECTION", newSelection);
|
|
27280
27342
|
this.processTokenAtCursor();
|
|
27281
27343
|
}
|
|
@@ -27442,7 +27504,7 @@ class Composer extends Component {
|
|
|
27442
27504
|
const highlights = this.env.model.getters.getHighlights();
|
|
27443
27505
|
const refSheet = sheetName
|
|
27444
27506
|
? this.env.model.getters.getSheetIdByName(sheetName)
|
|
27445
|
-
: this.env.model.getters.getCurrentEditedCell()
|
|
27507
|
+
: this.env.model.getters.getCurrentEditedCell()?.sheetId;
|
|
27446
27508
|
const highlight = highlights.find((highlight) => {
|
|
27447
27509
|
if (highlight.sheetId !== refSheet)
|
|
27448
27510
|
return false;
|
|
@@ -27569,56 +27631,30 @@ class GridComposer extends Component {
|
|
|
27569
27631
|
focus: {
|
|
27570
27632
|
validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value),
|
|
27571
27633
|
},
|
|
27572
|
-
|
|
27634
|
+
onComposerCellFocused: Function,
|
|
27573
27635
|
onComposerContentFocused: Function,
|
|
27574
27636
|
gridDims: Object,
|
|
27575
27637
|
};
|
|
27576
27638
|
static components = { Composer };
|
|
27577
|
-
|
|
27578
|
-
|
|
27579
|
-
rect;
|
|
27639
|
+
rect = this.defaultRect;
|
|
27640
|
+
isEditing = false;
|
|
27580
27641
|
isCellReferenceVisible;
|
|
27581
|
-
|
|
27642
|
+
get defaultRect() {
|
|
27643
|
+
return { x: 0, y: 0, width: 0, height: 0 };
|
|
27644
|
+
}
|
|
27582
27645
|
setup() {
|
|
27583
|
-
this.gridComposerRef = useRef("gridComposer");
|
|
27584
|
-
this.composerState = useState({
|
|
27585
|
-
rect: undefined,
|
|
27586
|
-
delimitation: undefined,
|
|
27587
|
-
});
|
|
27588
|
-
const { sheetId, col, row } = this.env.model.getters.getActivePosition();
|
|
27589
|
-
this.zone = this.env.model.getters.expandZone(sheetId, positionToZone({ col, row }));
|
|
27590
|
-
this.rect = this.env.model.getters.getVisibleRect(this.zone);
|
|
27591
|
-
this.isCellReferenceVisible = false;
|
|
27592
|
-
onMounted(() => {
|
|
27593
|
-
const el = this.gridComposerRef.el;
|
|
27594
|
-
this.composerState.rect = {
|
|
27595
|
-
x: this.rect.x,
|
|
27596
|
-
y: this.rect.y,
|
|
27597
|
-
width: el.clientWidth,
|
|
27598
|
-
height: el.clientHeight,
|
|
27599
|
-
};
|
|
27600
|
-
this.composerState.delimitation = {
|
|
27601
|
-
width: this.props.gridDims.width,
|
|
27602
|
-
height: this.props.gridDims.height,
|
|
27603
|
-
};
|
|
27604
|
-
});
|
|
27605
27646
|
onWillUpdateProps(() => {
|
|
27606
|
-
|
|
27607
|
-
|
|
27608
|
-
}
|
|
27609
|
-
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
27610
|
-
const zone = this.env.model.getters.getSelectedZone();
|
|
27611
|
-
const rect = this.env.model.getters.getVisibleRect(zone);
|
|
27612
|
-
if (!deepEquals(rect, this.rect) ||
|
|
27613
|
-
sheetId !== this.env.model.getters.getCurrentEditedCell().sheetId) {
|
|
27614
|
-
this.isCellReferenceVisible = true;
|
|
27615
|
-
}
|
|
27647
|
+
this.updateComponentPosition();
|
|
27648
|
+
this.updateCellReferenceVisibility();
|
|
27616
27649
|
});
|
|
27617
27650
|
}
|
|
27618
27651
|
get shouldDisplayCellReference() {
|
|
27619
27652
|
return this.isCellReferenceVisible;
|
|
27620
27653
|
}
|
|
27621
27654
|
get cellReference() {
|
|
27655
|
+
if (!this.env.model.getters.getCurrentEditedCell()) {
|
|
27656
|
+
return "";
|
|
27657
|
+
}
|
|
27622
27658
|
const { col, row, sheetId } = this.env.model.getters.getCurrentEditedCell();
|
|
27623
27659
|
const prefixSheet = sheetId !== this.env.model.getters.getActiveSheetId();
|
|
27624
27660
|
return getFullReference(prefixSheet ? this.env.model.getters.getSheetName(sheetId) : undefined, toXC(col, row));
|
|
@@ -27630,7 +27666,27 @@ class GridComposer extends Component {
|
|
|
27630
27666
|
top: `${top - GRID_CELL_REFERENCE_TOP_OFFSET}px`,
|
|
27631
27667
|
});
|
|
27632
27668
|
}
|
|
27669
|
+
get composerProps() {
|
|
27670
|
+
const { width, height } = this.env.model.getters.getSheetViewDimensionWithHeaders();
|
|
27671
|
+
return {
|
|
27672
|
+
rect: { ...this.rect },
|
|
27673
|
+
delimitation: {
|
|
27674
|
+
width,
|
|
27675
|
+
height,
|
|
27676
|
+
},
|
|
27677
|
+
focus: this.props.focus,
|
|
27678
|
+
isDefaultFocus: true,
|
|
27679
|
+
onComposerContentFocused: this.props.onComposerContentFocused,
|
|
27680
|
+
onComposerCellFocused: this.props.onComposerCellFocused,
|
|
27681
|
+
};
|
|
27682
|
+
}
|
|
27633
27683
|
get containerStyle() {
|
|
27684
|
+
if (this.env.model.getters.getEditionMode() === "inactive" || !this.rect) {
|
|
27685
|
+
return `
|
|
27686
|
+
position: absolute;
|
|
27687
|
+
z-index: -1000;
|
|
27688
|
+
`;
|
|
27689
|
+
}
|
|
27634
27690
|
const isFormula = this.env.model.getters.getCurrentContent().startsWith("=");
|
|
27635
27691
|
const cell = this.env.model.getters.getActiveCell();
|
|
27636
27692
|
const position = this.env.model.getters.getActivePosition();
|
|
@@ -27650,6 +27706,8 @@ class GridComposer extends Component {
|
|
|
27650
27706
|
if (!isFormula) {
|
|
27651
27707
|
textAlign = style.align || cell.defaultAlign;
|
|
27652
27708
|
}
|
|
27709
|
+
const maxHeight = this.props.gridDims.height - this.rect.y;
|
|
27710
|
+
const maxWidth = this.props.gridDims.width - this.rect.x;
|
|
27653
27711
|
/**
|
|
27654
27712
|
* min-size is on the container, not the composer element, because we want to have the same size as the cell by default,
|
|
27655
27713
|
* including all the paddings/margins of the composer
|
|
@@ -27661,6 +27719,8 @@ class GridComposer extends Component {
|
|
|
27661
27719
|
top: `${top}px`,
|
|
27662
27720
|
"min-width": `${width + 1}px`,
|
|
27663
27721
|
"min-height": `${height + 1}px`,
|
|
27722
|
+
"max-width": `${maxWidth}px`,
|
|
27723
|
+
"max-height": `${maxHeight}px`,
|
|
27664
27724
|
background,
|
|
27665
27725
|
color,
|
|
27666
27726
|
"font-size": `${fontSizeInPixels(fontSize)}px`,
|
|
@@ -27670,13 +27730,31 @@ class GridComposer extends Component {
|
|
|
27670
27730
|
"text-align": textAlign,
|
|
27671
27731
|
});
|
|
27672
27732
|
}
|
|
27673
|
-
|
|
27674
|
-
const
|
|
27675
|
-
|
|
27676
|
-
|
|
27677
|
-
|
|
27678
|
-
|
|
27679
|
-
|
|
27733
|
+
updateComponentPosition() {
|
|
27734
|
+
const isEditing = this.env.model.getters.getEditionMode() !== "inactive";
|
|
27735
|
+
if (this.isEditing !== isEditing) {
|
|
27736
|
+
this.isEditing = isEditing;
|
|
27737
|
+
if (!isEditing) {
|
|
27738
|
+
this.rect = this.defaultRect;
|
|
27739
|
+
this.env.focusableElement.focus();
|
|
27740
|
+
return;
|
|
27741
|
+
}
|
|
27742
|
+
const position = this.env.model.getters.getActivePosition();
|
|
27743
|
+
const zone = this.env.model.getters.expandZone(position.sheetId, positionToZone(position));
|
|
27744
|
+
this.rect = this.env.model.getters.getVisibleRect(zone);
|
|
27745
|
+
}
|
|
27746
|
+
}
|
|
27747
|
+
updateCellReferenceVisibility() {
|
|
27748
|
+
if (this.isCellReferenceVisible || this.env.model.getters.getEditionMode() === "inactive") {
|
|
27749
|
+
return;
|
|
27750
|
+
}
|
|
27751
|
+
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
27752
|
+
const zone = this.env.model.getters.getSelectedZone();
|
|
27753
|
+
const rect = this.env.model.getters.getVisibleRect(zone);
|
|
27754
|
+
if (!deepEquals(rect, this.rect) ||
|
|
27755
|
+
sheetId !== this.env.model.getters.getCurrentEditedCell().sheetId) {
|
|
27756
|
+
this.isCellReferenceVisible = true;
|
|
27757
|
+
}
|
|
27680
27758
|
}
|
|
27681
27759
|
}
|
|
27682
27760
|
|
|
@@ -28776,7 +28854,6 @@ class GridOverlay extends Component {
|
|
|
28776
28854
|
this.props.onCellDoubleClicked(col, row);
|
|
28777
28855
|
}
|
|
28778
28856
|
onContextMenu(ev) {
|
|
28779
|
-
ev.preventDefault();
|
|
28780
28857
|
const [col, row] = this.getCartesianCoordinates(ev);
|
|
28781
28858
|
this.props.onCellRightClicked(col, row, { x: ev.clientX, y: ev.clientY });
|
|
28782
28859
|
}
|
|
@@ -29841,7 +29918,6 @@ class Grid extends Component {
|
|
|
29841
29918
|
HEADER_WIDTH = HEADER_WIDTH;
|
|
29842
29919
|
menuState;
|
|
29843
29920
|
gridRef;
|
|
29844
|
-
hiddenInput;
|
|
29845
29921
|
onMouseWheel;
|
|
29846
29922
|
canvasPosition;
|
|
29847
29923
|
hoveredCell;
|
|
@@ -29852,15 +29928,14 @@ class Grid extends Component {
|
|
|
29852
29928
|
menuItems: [],
|
|
29853
29929
|
});
|
|
29854
29930
|
this.gridRef = useRef("grid");
|
|
29855
|
-
this.hiddenInput = useRef("hiddenInput");
|
|
29856
29931
|
this.canvasPosition = useAbsoluteBoundingRect(this.gridRef);
|
|
29857
29932
|
this.hoveredCell = useState({ col: undefined, row: undefined });
|
|
29858
29933
|
useChildSubEnv({ getPopoverContainerRect: () => this.getGridRect() });
|
|
29859
29934
|
useExternalListener(document.body, "cut", this.copy.bind(this, true));
|
|
29860
29935
|
useExternalListener(document.body, "copy", this.copy.bind(this, false));
|
|
29861
29936
|
useExternalListener(document.body, "paste", this.paste);
|
|
29862
|
-
onMounted(() => this.
|
|
29863
|
-
this.props.exposeFocus(() => this.
|
|
29937
|
+
onMounted(() => this.focusDefaultElement());
|
|
29938
|
+
this.props.exposeFocus(() => this.focusDefaultElement());
|
|
29864
29939
|
useGridDrawing("canvas", this.env.model, () => this.env.model.getters.getSheetViewDimensionWithHeaders());
|
|
29865
29940
|
this.onMouseWheel = useWheelHandler((deltaX, deltaY) => {
|
|
29866
29941
|
this.moveCanvas(deltaX, deltaY);
|
|
@@ -29884,7 +29959,7 @@ class Grid extends Component {
|
|
|
29884
29959
|
if (this.env.model.getters.hasOpenedPopover()) {
|
|
29885
29960
|
this.closeOpenedPopover();
|
|
29886
29961
|
}
|
|
29887
|
-
this.
|
|
29962
|
+
this.focusDefaultElement();
|
|
29888
29963
|
}
|
|
29889
29964
|
// this map will handle most of the actions that should happen on key down. The arrow keys are managed in the key
|
|
29890
29965
|
// down itself
|
|
@@ -30063,10 +30138,10 @@ class Grid extends Component {
|
|
|
30063
30138
|
"Alt+Shift+ArrowUp": () => this.processHeaderGroupingKey("up"),
|
|
30064
30139
|
"Alt+Shift+ArrowDown": () => this.processHeaderGroupingKey("down"),
|
|
30065
30140
|
};
|
|
30066
|
-
|
|
30141
|
+
focusDefaultElement() {
|
|
30067
30142
|
if (!this.env.model.getters.getSelectedFigureId() &&
|
|
30068
30143
|
this.env.model.getters.getEditionMode() === "inactive") {
|
|
30069
|
-
this.
|
|
30144
|
+
this.env.focusableElement.focus();
|
|
30070
30145
|
}
|
|
30071
30146
|
}
|
|
30072
30147
|
get gridEl() {
|
|
@@ -30202,19 +30277,6 @@ class Grid extends Component {
|
|
|
30202
30277
|
return;
|
|
30203
30278
|
}
|
|
30204
30279
|
}
|
|
30205
|
-
onInput(ev) {
|
|
30206
|
-
// the user meant to paste in the sheet, not open the composer with the pasted content
|
|
30207
|
-
if (!ev.isComposing && ev.inputType === "insertFromPaste") {
|
|
30208
|
-
return;
|
|
30209
|
-
}
|
|
30210
|
-
if (ev.data) {
|
|
30211
|
-
// if the user types a character on the grid, it means he wants to start composing the selected cell with that
|
|
30212
|
-
// character
|
|
30213
|
-
ev.preventDefault();
|
|
30214
|
-
ev.stopPropagation();
|
|
30215
|
-
this.props.onGridComposerCellFocused(ev.data);
|
|
30216
|
-
}
|
|
30217
|
-
}
|
|
30218
30280
|
// ---------------------------------------------------------------------------
|
|
30219
30281
|
// Context Menu
|
|
30220
30282
|
// ---------------------------------------------------------------------------
|
|
@@ -30329,7 +30391,7 @@ class Grid extends Component {
|
|
|
30329
30391
|
}
|
|
30330
30392
|
closeMenu() {
|
|
30331
30393
|
this.menuState.isOpen = false;
|
|
30332
|
-
this.
|
|
30394
|
+
this.focusDefaultElement();
|
|
30333
30395
|
}
|
|
30334
30396
|
processHeaderGroupingKey(direction) {
|
|
30335
30397
|
if (this.env.model.getters.getSelectedZones().length !== 1) {
|
|
@@ -34246,6 +34308,31 @@ const MIGRATIONS = [
|
|
|
34246
34308
|
return data;
|
|
34247
34309
|
},
|
|
34248
34310
|
},
|
|
34311
|
+
{
|
|
34312
|
+
description: "Fix datafilter duplication",
|
|
34313
|
+
from: 12,
|
|
34314
|
+
to: 12.5,
|
|
34315
|
+
applyMigration(data) {
|
|
34316
|
+
for (let sheet of data.sheets || []) {
|
|
34317
|
+
let knownDataFilterZones = [];
|
|
34318
|
+
for (let filterTable of sheet.filterTables || []) {
|
|
34319
|
+
const zone = toZone(filterTable.range);
|
|
34320
|
+
// See commit message for the details
|
|
34321
|
+
const intersectZoneIndex = knownDataFilterZones.findIndex((knownZone) => overlap(knownZone, zone));
|
|
34322
|
+
if (intersectZoneIndex !== -1) {
|
|
34323
|
+
knownDataFilterZones[intersectZoneIndex] = zone;
|
|
34324
|
+
}
|
|
34325
|
+
else {
|
|
34326
|
+
knownDataFilterZones.push(zone);
|
|
34327
|
+
}
|
|
34328
|
+
}
|
|
34329
|
+
sheet.filterTables = knownDataFilterZones.map((zone) => ({
|
|
34330
|
+
range: zoneToXc(zone),
|
|
34331
|
+
}));
|
|
34332
|
+
}
|
|
34333
|
+
return data;
|
|
34334
|
+
},
|
|
34335
|
+
},
|
|
34249
34336
|
{
|
|
34250
34337
|
description: "Change Border description structure",
|
|
34251
34338
|
from: 12,
|
|
@@ -35085,22 +35172,7 @@ class BordersPlugin extends CorePlugin {
|
|
|
35085
35172
|
}
|
|
35086
35173
|
}
|
|
35087
35174
|
export(data) {
|
|
35088
|
-
// Borders
|
|
35089
|
-
let borderId = 0;
|
|
35090
35175
|
const borders = {};
|
|
35091
|
-
/**
|
|
35092
|
-
* Get the id of the given border. If the border does not exist, it creates
|
|
35093
|
-
* one.
|
|
35094
|
-
*/
|
|
35095
|
-
function getBorderId(border) {
|
|
35096
|
-
for (let [key, value] of Object.entries(borders)) {
|
|
35097
|
-
if (deepEquals(value, border)) {
|
|
35098
|
-
return parseInt(key, 10);
|
|
35099
|
-
}
|
|
35100
|
-
}
|
|
35101
|
-
borders[++borderId] = border;
|
|
35102
|
-
return borderId;
|
|
35103
|
-
}
|
|
35104
35176
|
for (let sheet of data.sheets) {
|
|
35105
35177
|
for (let col = 0; col < sheet.colNumber; col++) {
|
|
35106
35178
|
for (let row = 0; row < sheet.rowNumber; row++) {
|
|
@@ -35108,7 +35180,7 @@ class BordersPlugin extends CorePlugin {
|
|
|
35108
35180
|
if (border) {
|
|
35109
35181
|
const xc = toXC(col, row);
|
|
35110
35182
|
const cell = sheet.cells[xc];
|
|
35111
|
-
const borderId =
|
|
35183
|
+
const borderId = getItemId(border, borders);
|
|
35112
35184
|
if (cell) {
|
|
35113
35185
|
cell.border = borderId;
|
|
35114
35186
|
}
|
|
@@ -35897,9 +35969,9 @@ class CellPlugin extends CorePlugin {
|
|
|
35897
35969
|
allowDispatch(cmd) {
|
|
35898
35970
|
switch (cmd.type) {
|
|
35899
35971
|
case "UPDATE_CELL":
|
|
35900
|
-
return this.
|
|
35972
|
+
return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessUpdateCell);
|
|
35901
35973
|
case "CLEAR_CELL":
|
|
35902
|
-
return this.checkValidations(cmd, this.
|
|
35974
|
+
return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessClearCell);
|
|
35903
35975
|
default:
|
|
35904
35976
|
return "Success" /* CommandResult.Success */;
|
|
35905
35977
|
}
|
|
@@ -36032,9 +36104,6 @@ class CellPlugin extends CorePlugin {
|
|
|
36032
36104
|
format: cell.format ? getItemId(cell.format, formats) : undefined,
|
|
36033
36105
|
content: cell.content || undefined,
|
|
36034
36106
|
};
|
|
36035
|
-
if (cell instanceof FormulaCellWithDependencies) {
|
|
36036
|
-
cells[xc].content = cell.contentWithFixedReferences || undefined;
|
|
36037
|
-
}
|
|
36038
36107
|
}
|
|
36039
36108
|
_sheet.cells = cells;
|
|
36040
36109
|
}
|
|
@@ -36052,8 +36121,8 @@ class CellPlugin extends CorePlugin {
|
|
|
36052
36121
|
}
|
|
36053
36122
|
removeDefaultStyleValues(style) {
|
|
36054
36123
|
const cleanedStyle = { ...style };
|
|
36055
|
-
for (const
|
|
36056
|
-
if (cleanedStyle[property] ===
|
|
36124
|
+
for (const property in DEFAULT_STYLE) {
|
|
36125
|
+
if (cleanedStyle[property] === DEFAULT_STYLE[property]) {
|
|
36057
36126
|
delete cleanedStyle[property];
|
|
36058
36127
|
}
|
|
36059
36128
|
}
|
|
@@ -36209,10 +36278,7 @@ class CellPlugin extends CorePlugin {
|
|
|
36209
36278
|
else {
|
|
36210
36279
|
style = before ? before.style : undefined;
|
|
36211
36280
|
}
|
|
36212
|
-
const
|
|
36213
|
-
let format = ("format" in after ? after.format : before && before.format) ||
|
|
36214
|
-
detectDateFormat(afterContent, locale) ||
|
|
36215
|
-
detectNumberFormat(afterContent);
|
|
36281
|
+
const format = "format" in after ? after.format : before && before.format;
|
|
36216
36282
|
/* Read the following IF as:
|
|
36217
36283
|
* we need to remove the cell if it is completely empty, but we can know if it completely empty if:
|
|
36218
36284
|
* - the command says the new content is empty and has no border/format/style
|
|
@@ -36253,6 +36319,7 @@ class CellPlugin extends CorePlugin {
|
|
|
36253
36319
|
}
|
|
36254
36320
|
createLiteralCell(id, content, format, style) {
|
|
36255
36321
|
const locale = this.getters.getLocale();
|
|
36322
|
+
format = format || detectDateFormat(content, locale) || detectNumberFormat(content);
|
|
36256
36323
|
if (format !== PLAIN_TEXT_FORMAT && !isEvaluationError(content)) {
|
|
36257
36324
|
content = toString(parseLiteral(content, locale));
|
|
36258
36325
|
}
|
|
@@ -36286,8 +36353,11 @@ class CellPlugin extends CorePlugin {
|
|
|
36286
36353
|
* being a computed property to rebuild the dependencies XC.
|
|
36287
36354
|
*/
|
|
36288
36355
|
createFormulaCellWithDependencies(id, compiledFormula, format, style, sheetId) {
|
|
36289
|
-
const dependencies =
|
|
36290
|
-
|
|
36356
|
+
const dependencies = [];
|
|
36357
|
+
for (const xc of compiledFormula.dependencies) {
|
|
36358
|
+
dependencies.push(this.getters.getRangeFromSheetXC(sheetId, xc));
|
|
36359
|
+
}
|
|
36360
|
+
return new FormulaCellWithDependencies(id, compiledFormula, format, style, dependencies, sheetId, this.getters.getRangeString);
|
|
36291
36361
|
}
|
|
36292
36362
|
createErrorFormula(id, content, format, style, error) {
|
|
36293
36363
|
return {
|
|
@@ -36322,6 +36392,18 @@ class CellPlugin extends CorePlugin {
|
|
|
36322
36392
|
}
|
|
36323
36393
|
return "Success" /* CommandResult.Success */;
|
|
36324
36394
|
}
|
|
36395
|
+
checkUselessUpdateCell(cmd) {
|
|
36396
|
+
const cell = this.getters.getCell(cmd);
|
|
36397
|
+
const hasContent = "content" in cmd || "formula" in cmd;
|
|
36398
|
+
const hasStyle = "style" in cmd;
|
|
36399
|
+
const hasFormat = "format" in cmd;
|
|
36400
|
+
if ((!hasContent || cell?.content === cmd.content) &&
|
|
36401
|
+
(!hasStyle || deepEquals(cell?.style, cmd.style)) &&
|
|
36402
|
+
(!hasFormat || cell?.format === cmd.format)) {
|
|
36403
|
+
return "NoChanges" /* CommandResult.NoChanges */;
|
|
36404
|
+
}
|
|
36405
|
+
return "Success" /* CommandResult.Success */;
|
|
36406
|
+
}
|
|
36325
36407
|
}
|
|
36326
36408
|
class FormulaCellWithDependencies {
|
|
36327
36409
|
id;
|
|
@@ -36341,7 +36423,7 @@ class FormulaCellWithDependencies {
|
|
|
36341
36423
|
const tokens = compiledFormula.tokens.map((token) => {
|
|
36342
36424
|
if (token.type === "REFERENCE") {
|
|
36343
36425
|
const index = rangeIndex++;
|
|
36344
|
-
return new RangeReferenceToken(
|
|
36426
|
+
return new RangeReferenceToken(dependencies, index, this.sheetId, this.getRangeString);
|
|
36345
36427
|
}
|
|
36346
36428
|
return token;
|
|
36347
36429
|
});
|
|
@@ -36368,13 +36450,20 @@ class FormulaCellWithDependencies {
|
|
|
36368
36450
|
}
|
|
36369
36451
|
}
|
|
36370
36452
|
class RangeReferenceToken {
|
|
36371
|
-
|
|
36453
|
+
ranges;
|
|
36454
|
+
rangeIndex;
|
|
36455
|
+
sheetId;
|
|
36456
|
+
getRangeString;
|
|
36372
36457
|
type = "REFERENCE";
|
|
36373
|
-
constructor(
|
|
36374
|
-
this.
|
|
36458
|
+
constructor(ranges, rangeIndex, sheetId, getRangeString) {
|
|
36459
|
+
this.ranges = ranges;
|
|
36460
|
+
this.rangeIndex = rangeIndex;
|
|
36461
|
+
this.sheetId = sheetId;
|
|
36462
|
+
this.getRangeString = getRangeString;
|
|
36375
36463
|
}
|
|
36376
36464
|
get value() {
|
|
36377
|
-
|
|
36465
|
+
const range = this.ranges[this.rangeIndex];
|
|
36466
|
+
return this.getRangeString(range, this.sheetId);
|
|
36378
36467
|
}
|
|
36379
36468
|
}
|
|
36380
36469
|
|
|
@@ -41099,7 +41188,15 @@ class SpreadsheetRTree {
|
|
|
41099
41188
|
if (!this.rTrees[sheetId]) {
|
|
41100
41189
|
return;
|
|
41101
41190
|
}
|
|
41102
|
-
this.rTrees[sheetId].remove(item,
|
|
41191
|
+
this.rTrees[sheetId].remove(item, this.rtreeItemComparer);
|
|
41192
|
+
}
|
|
41193
|
+
rtreeItemComparer(left, right) {
|
|
41194
|
+
return (left.data == right.data &&
|
|
41195
|
+
left.boundingBox.sheetId === right.boundingBox.sheetId &&
|
|
41196
|
+
left.boundingBox?.zone.left === right.boundingBox.zone.left &&
|
|
41197
|
+
left.boundingBox?.zone.top === right.boundingBox.zone.top &&
|
|
41198
|
+
left.boundingBox?.zone.right === right.boundingBox.zone.right &&
|
|
41199
|
+
left.boundingBox?.zone.bottom === right.boundingBox.zone.bottom);
|
|
41103
41200
|
}
|
|
41104
41201
|
}
|
|
41105
41202
|
/**
|
|
@@ -41177,7 +41274,7 @@ class FormulaDependencyGraph {
|
|
|
41177
41274
|
const queue = Array.from(ranges).reverse();
|
|
41178
41275
|
while (queue.length > 0) {
|
|
41179
41276
|
const range = queue.pop();
|
|
41180
|
-
visited.
|
|
41277
|
+
visited.addMany(this.encoder.encodeBoundingBox(range));
|
|
41181
41278
|
const impactedPositionIds = this.rTree.search(range).map((dep) => dep.data);
|
|
41182
41279
|
for (const positionId of impactedPositionIds) {
|
|
41183
41280
|
if (!visited.has(positionId)) {
|
|
@@ -41185,7 +41282,7 @@ class FormulaDependencyGraph {
|
|
|
41185
41282
|
}
|
|
41186
41283
|
}
|
|
41187
41284
|
}
|
|
41188
|
-
visited.
|
|
41285
|
+
visited.deleteMany(ranges.flatMap((r) => this.encoder.encodeBoundingBox(r)));
|
|
41189
41286
|
return visited;
|
|
41190
41287
|
}
|
|
41191
41288
|
}
|
|
@@ -41325,9 +41422,9 @@ class Evaluator {
|
|
|
41325
41422
|
const cells = positions.map((p) => this.encoder.encode(p));
|
|
41326
41423
|
const cellsToCompute = new JetSet(cells);
|
|
41327
41424
|
const arrayFormulasPositionIds = this.getArrayFormulasImpactedByChangesOf(cells);
|
|
41328
|
-
cellsToCompute.
|
|
41329
|
-
cellsToCompute.
|
|
41330
|
-
cellsToCompute.
|
|
41425
|
+
cellsToCompute.addMany(this.getCellsDependingOn(cells));
|
|
41426
|
+
cellsToCompute.addMany(arrayFormulasPositionIds);
|
|
41427
|
+
cellsToCompute.addMany(this.getCellsDependingOn(arrayFormulasPositionIds));
|
|
41331
41428
|
this.evaluate(cellsToCompute);
|
|
41332
41429
|
}
|
|
41333
41430
|
getArrayFormulasImpactedByChangesOf(positionIds) {
|
|
@@ -41341,7 +41438,7 @@ class Evaluator {
|
|
|
41341
41438
|
}
|
|
41342
41439
|
if (!content) {
|
|
41343
41440
|
// The previous content could have blocked some array formulas
|
|
41344
|
-
impactedPositionIds.
|
|
41441
|
+
impactedPositionIds.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(positionId));
|
|
41345
41442
|
}
|
|
41346
41443
|
}
|
|
41347
41444
|
return impactedPositionIds;
|
|
@@ -41393,7 +41490,7 @@ class Evaluator {
|
|
|
41393
41490
|
}
|
|
41394
41491
|
const arrayFormulas = this.spreadingRelations.getFormulaPositionsSpreadingOn(positionId);
|
|
41395
41492
|
const cells = new JetSet(arrayFormulas);
|
|
41396
|
-
cells.
|
|
41493
|
+
cells.addMany(this.getCellsDependingOn(arrayFormulas));
|
|
41397
41494
|
return cells;
|
|
41398
41495
|
}
|
|
41399
41496
|
nextPositionsToUpdate = new JetSet();
|
|
@@ -41531,7 +41628,7 @@ class Evaluator {
|
|
|
41531
41628
|
this.setEvaluatedCell(positionId, evaluatedCell);
|
|
41532
41629
|
// check if formula dependencies present in the spread zone
|
|
41533
41630
|
// if so, they need to be recomputed
|
|
41534
|
-
this.nextPositionsToUpdate.
|
|
41631
|
+
this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([positionId]));
|
|
41535
41632
|
};
|
|
41536
41633
|
}
|
|
41537
41634
|
invalidateSpreading(positionId) {
|
|
@@ -41546,8 +41643,8 @@ class Evaluator {
|
|
|
41546
41643
|
continue;
|
|
41547
41644
|
}
|
|
41548
41645
|
this.evaluatedCells.delete(child);
|
|
41549
|
-
this.nextPositionsToUpdate.
|
|
41550
|
-
this.nextPositionsToUpdate.
|
|
41646
|
+
this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([child]));
|
|
41647
|
+
this.nextPositionsToUpdate.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(child));
|
|
41551
41648
|
}
|
|
41552
41649
|
this.spreadingRelations.removeNode(positionId);
|
|
41553
41650
|
}
|
|
@@ -41909,7 +42006,13 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
41909
42006
|
const format = newFormat
|
|
41910
42007
|
? getItemId(newFormat, data.formats)
|
|
41911
42008
|
: exportedCellData.format;
|
|
41912
|
-
|
|
42009
|
+
let content;
|
|
42010
|
+
if (formulaCell instanceof FormulaCellWithDependencies) {
|
|
42011
|
+
content = formulaCell.contentWithFixedReferences;
|
|
42012
|
+
}
|
|
42013
|
+
else {
|
|
42014
|
+
content = !isExported ? newContent : exportedCellData.content;
|
|
42015
|
+
}
|
|
41913
42016
|
exportedSheetData.cells[xc] = { ...exportedCellData, value, isFormula, content, format };
|
|
41914
42017
|
}
|
|
41915
42018
|
}
|
|
@@ -45410,7 +45513,7 @@ class FindAndReplacePlugin extends UIPlugin {
|
|
|
45410
45513
|
}
|
|
45411
45514
|
finalize() {
|
|
45412
45515
|
if (this.isSearchDirty) {
|
|
45413
|
-
this.refreshSearch();
|
|
45516
|
+
this.refreshSearch(false);
|
|
45414
45517
|
this.isSearchDirty = false;
|
|
45415
45518
|
}
|
|
45416
45519
|
}
|
|
@@ -45454,10 +45557,10 @@ class FindAndReplacePlugin extends UIPlugin {
|
|
|
45454
45557
|
/**
|
|
45455
45558
|
* refresh the matches according to the current search options
|
|
45456
45559
|
*/
|
|
45457
|
-
refreshSearch() {
|
|
45560
|
+
refreshSearch(jumpToMatchSheet = true) {
|
|
45458
45561
|
this.selectedMatchIndex = null;
|
|
45459
45562
|
this.findMatches();
|
|
45460
|
-
this.selectNextCell(Direction.current);
|
|
45563
|
+
this.selectNextCell(Direction.current, jumpToMatchSheet);
|
|
45461
45564
|
}
|
|
45462
45565
|
/**
|
|
45463
45566
|
* Updates the regex based on the current searchOptions and
|
|
@@ -45539,7 +45642,7 @@ class FindAndReplacePlugin extends UIPlugin {
|
|
|
45539
45642
|
* It is also used to keep coherence between the selected searchMatch
|
|
45540
45643
|
* and selectedMatchIndex.
|
|
45541
45644
|
*/
|
|
45542
|
-
selectNextCell(indexChange) {
|
|
45645
|
+
selectNextCell(indexChange, jumpToMatchSheet = true) {
|
|
45543
45646
|
const matches = this.searchMatches;
|
|
45544
45647
|
if (!matches.length) {
|
|
45545
45648
|
this.selectedMatchIndex = null;
|
|
@@ -45565,7 +45668,7 @@ class FindAndReplacePlugin extends UIPlugin {
|
|
|
45565
45668
|
this.selectedMatchIndex = nextIndex;
|
|
45566
45669
|
const selectedMatch = matches[nextIndex];
|
|
45567
45670
|
// Switch to the sheet where the match is located
|
|
45568
|
-
if (this.getters.getActiveSheetId() !== selectedMatch.sheetId) {
|
|
45671
|
+
if (jumpToMatchSheet && this.getters.getActiveSheetId() !== selectedMatch.sheetId) {
|
|
45569
45672
|
this.dispatch("ACTIVATE_SHEET", {
|
|
45570
45673
|
sheetIdFrom: this.getters.getActiveSheetId(),
|
|
45571
45674
|
sheetIdTo: selectedMatch.sheetId,
|
|
@@ -47137,7 +47240,7 @@ class SheetUIPlugin extends UIPlugin {
|
|
|
47137
47240
|
"getCellText",
|
|
47138
47241
|
"getCellMultiLineText",
|
|
47139
47242
|
"getContiguousZone",
|
|
47140
|
-
"
|
|
47243
|
+
"isEvaluatedCellEmpty",
|
|
47141
47244
|
];
|
|
47142
47245
|
ctx = document.createElement("canvas").getContext("2d");
|
|
47143
47246
|
// ---------------------------------------------------------------------------
|
|
@@ -47265,14 +47368,23 @@ class SheetUIPlugin extends UIPlugin {
|
|
|
47265
47368
|
return zone;
|
|
47266
47369
|
}
|
|
47267
47370
|
/**
|
|
47268
|
-
*
|
|
47269
|
-
* check
|
|
47371
|
+
* Checks if a cell evaluated value is empty. If the cell is part of a merge,
|
|
47372
|
+
* the check applies to the main cell of the merge.
|
|
47270
47373
|
*/
|
|
47271
|
-
|
|
47374
|
+
isEvaluatedCellEmpty(position) {
|
|
47272
47375
|
const mainPosition = this.getters.getMainCellPosition(position);
|
|
47273
47376
|
const cell = this.getters.getEvaluatedCell(mainPosition);
|
|
47274
47377
|
return cell.type === CellValueType.empty;
|
|
47275
47378
|
}
|
|
47379
|
+
/**
|
|
47380
|
+
* Checks if a cell is empty (i.e. does not have a content or a formula does not spread over it).
|
|
47381
|
+
* If the cell is part of a merge, the check applies to the main cell of the merge.
|
|
47382
|
+
*/
|
|
47383
|
+
isCellEmpty(position) {
|
|
47384
|
+
const mainPosition = this.getters.getMainCellPosition(position);
|
|
47385
|
+
return !(this.getters.getCorrespondingFormulaCell(mainPosition) ||
|
|
47386
|
+
this.getters.getCell(mainPosition)?.content);
|
|
47387
|
+
}
|
|
47276
47388
|
getColMaxWidth(sheetId, index) {
|
|
47277
47389
|
const cellsPositions = positions(this.getters.getColsZone(sheetId, index, index));
|
|
47278
47390
|
const sizes = cellsPositions.map((position) => this.getCellWidth({ sheetId, ...position }));
|
|
@@ -51093,6 +51205,16 @@ class ImageProvider {
|
|
|
51093
51205
|
}
|
|
51094
51206
|
}
|
|
51095
51207
|
|
|
51208
|
+
class FocusableElement {
|
|
51209
|
+
focusableElement = undefined;
|
|
51210
|
+
setFocusableElement(element) {
|
|
51211
|
+
this.focusableElement = element;
|
|
51212
|
+
}
|
|
51213
|
+
focus() {
|
|
51214
|
+
this.focusableElement?.focus();
|
|
51215
|
+
}
|
|
51216
|
+
}
|
|
51217
|
+
|
|
51096
51218
|
const RIPPLE_KEY_FRAMES = [
|
|
51097
51219
|
{ transform: "scale(0)" },
|
|
51098
51220
|
{ transform: "scale(0.8)", offset: 0.33 },
|
|
@@ -53247,6 +53369,7 @@ class Spreadsheet extends Component {
|
|
|
53247
53369
|
toggleSidePanel: this.toggleSidePanel.bind(this),
|
|
53248
53370
|
clipboard: this.env.clipboard || instantiateClipboard(),
|
|
53249
53371
|
startCellEdition: (content) => this.onGridComposerCellFocused(content),
|
|
53372
|
+
focusableElement: new FocusableElement(),
|
|
53250
53373
|
});
|
|
53251
53374
|
useEffect(() => {
|
|
53252
53375
|
/**
|
|
@@ -53365,16 +53488,17 @@ class Spreadsheet extends Component {
|
|
|
53365
53488
|
}
|
|
53366
53489
|
this.composer.topBarFocus = "contentFocus";
|
|
53367
53490
|
this.composer.gridFocusMode = "inactive";
|
|
53368
|
-
this.setComposerContent({ selection }
|
|
53491
|
+
this.setComposerContent({ selection });
|
|
53369
53492
|
}
|
|
53370
|
-
onGridComposerContentFocused() {
|
|
53493
|
+
onGridComposerContentFocused(selection) {
|
|
53371
53494
|
if (this.model.getters.isReadonly()) {
|
|
53372
53495
|
return;
|
|
53373
53496
|
}
|
|
53374
53497
|
this.composer.topBarFocus = "inactive";
|
|
53375
53498
|
this.composer.gridFocusMode = "contentFocus";
|
|
53376
|
-
this.setComposerContent({});
|
|
53499
|
+
this.setComposerContent({ selection });
|
|
53377
53500
|
}
|
|
53501
|
+
// TODO: either both are defined or none of them. change those args to an object
|
|
53378
53502
|
onGridComposerCellFocused(content, selection) {
|
|
53379
53503
|
if (this.model.getters.isReadonly()) {
|
|
53380
53504
|
return;
|
|
@@ -54802,8 +54926,8 @@ class SelectionStreamProcessorImpl {
|
|
|
54802
54926
|
let currentPosition = startPosition;
|
|
54803
54927
|
// If both the current cell and the next cell are not empty, we want to go to the end of the cluster
|
|
54804
54928
|
const nextCellPosition = this.getNextCellPosition(startPosition, dim, dir);
|
|
54805
|
-
let mode = !this.getters.
|
|
54806
|
-
!this.getters.
|
|
54929
|
+
let mode = !this.getters.isEvaluatedCellEmpty({ ...currentPosition, sheetId }) &&
|
|
54930
|
+
!this.getters.isEvaluatedCellEmpty({ ...nextCellPosition, sheetId })
|
|
54807
54931
|
? "endOfCluster"
|
|
54808
54932
|
: "nextCluster";
|
|
54809
54933
|
while (true) {
|
|
@@ -54813,7 +54937,7 @@ class SelectionStreamProcessorImpl {
|
|
|
54813
54937
|
currentPosition.row === nextCellPosition.row) {
|
|
54814
54938
|
break;
|
|
54815
54939
|
}
|
|
54816
|
-
const isNextCellEmpty = this.getters.
|
|
54940
|
+
const isNextCellEmpty = this.getters.isEvaluatedCellEmpty({ ...nextCellPosition, sheetId });
|
|
54817
54941
|
if (mode === "endOfCluster" && isNextCellEmpty) {
|
|
54818
54942
|
break;
|
|
54819
54943
|
}
|
|
@@ -57062,6 +57186,6 @@ const constants = {
|
|
|
57062
57186
|
export { AbstractChart, CellErrorType, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, tokenize };
|
|
57063
57187
|
|
|
57064
57188
|
|
|
57065
|
-
__info__.version = "17.1.
|
|
57066
|
-
__info__.date = "2024-02-
|
|
57067
|
-
__info__.hash = "
|
|
57189
|
+
__info__.version = "17.1.5";
|
|
57190
|
+
__info__.date = "2024-02-16T14:23:54.651Z";
|
|
57191
|
+
__info__.hash = "29d8ad6";
|