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