@odoo/o-spreadsheet 17.0.10 → 17.0.13
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 +348 -206
- package/dist/o-spreadsheet.d.ts +31 -15
- package/dist/o-spreadsheet.esm.js +348 -206
- package/dist/o-spreadsheet.iife.js +348 -206
- package/dist/o-spreadsheet.iife.min.js +261 -260
- 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.0.
|
|
6
|
-
* @date 2024-02-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 17.0.13
|
|
6
|
+
* @date 2024-02-28T12:28:44.914Z
|
|
7
|
+
* @hash ed67be7
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
(function (exports, owl) {
|
|
@@ -551,8 +551,8 @@
|
|
|
551
551
|
* If the given item does not exist in the dictionary, it creates one with a new id.
|
|
552
552
|
*/
|
|
553
553
|
function getItemId(item, itemsDic) {
|
|
554
|
-
for (
|
|
555
|
-
if (deepEquals(
|
|
554
|
+
for (const key in itemsDic) {
|
|
555
|
+
if (deepEquals(itemsDic[key], item)) {
|
|
556
556
|
return parseInt(key, 10);
|
|
557
557
|
}
|
|
558
558
|
}
|
|
@@ -651,11 +651,13 @@
|
|
|
651
651
|
if (typeof o1 !== "object")
|
|
652
652
|
return o1 === o2;
|
|
653
653
|
// Objects can have different keys if the values are undefined
|
|
654
|
-
const
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
654
|
+
for (const key in o2) {
|
|
655
|
+
if (!(key in o1) && o2[key] !== undefined) {
|
|
656
|
+
return false;
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
for (const key in o1) {
|
|
660
|
+
if (typeof o1[key] !== typeof o2[key])
|
|
659
661
|
return false;
|
|
660
662
|
if (typeof o1[key] === "object") {
|
|
661
663
|
if (!deepEquals(o1[key], o2[key]))
|
|
@@ -725,18 +727,18 @@
|
|
|
725
727
|
return true;
|
|
726
728
|
}
|
|
727
729
|
class JetSet extends Set {
|
|
728
|
-
|
|
730
|
+
addMany(iterable) {
|
|
729
731
|
for (const element of iterable) {
|
|
730
732
|
super.add(element);
|
|
731
733
|
}
|
|
732
734
|
return this;
|
|
733
735
|
}
|
|
734
|
-
|
|
735
|
-
let
|
|
736
|
+
deleteMany(iterable) {
|
|
737
|
+
let wasDeleted = false;
|
|
736
738
|
for (const element of iterable) {
|
|
737
|
-
|
|
739
|
+
wasDeleted ||= super.delete(element);
|
|
738
740
|
}
|
|
739
|
-
return
|
|
741
|
+
return wasDeleted;
|
|
740
742
|
}
|
|
741
743
|
}
|
|
742
744
|
/**
|
|
@@ -1995,7 +1997,7 @@
|
|
|
1995
1997
|
* Static helper which returns a successful DispatchResult
|
|
1996
1998
|
*/
|
|
1997
1999
|
static get Success() {
|
|
1998
|
-
return
|
|
2000
|
+
return SUCCESS;
|
|
1999
2001
|
}
|
|
2000
2002
|
get isSuccessful() {
|
|
2001
2003
|
return this.reasons.length === 0;
|
|
@@ -2008,6 +2010,7 @@
|
|
|
2008
2010
|
return this.reasons.includes(reason);
|
|
2009
2011
|
}
|
|
2010
2012
|
}
|
|
2013
|
+
const SUCCESS = new DispatchResult();
|
|
2011
2014
|
exports.CommandResult = void 0;
|
|
2012
2015
|
(function (CommandResult) {
|
|
2013
2016
|
CommandResult["Success"] = "Success";
|
|
@@ -2889,6 +2892,9 @@
|
|
|
2889
2892
|
function formatValue(value, { format, locale }) {
|
|
2890
2893
|
switch (typeof value) {
|
|
2891
2894
|
case "string":
|
|
2895
|
+
if (value.includes('\\"')) {
|
|
2896
|
+
return value.replace(/\\"/g, '"');
|
|
2897
|
+
}
|
|
2892
2898
|
return value;
|
|
2893
2899
|
case "boolean":
|
|
2894
2900
|
return value ? "TRUE" : "FALSE";
|
|
@@ -6277,11 +6283,14 @@
|
|
|
6277
6283
|
* Transform CSS properties into a CSS string.
|
|
6278
6284
|
*/
|
|
6279
6285
|
function cssPropertiesToCss(attributes) {
|
|
6280
|
-
|
|
6281
|
-
|
|
6282
|
-
|
|
6283
|
-
|
|
6284
|
-
|
|
6286
|
+
let styleStr = "";
|
|
6287
|
+
for (const attName in attributes) {
|
|
6288
|
+
if (!attributes[attName]) {
|
|
6289
|
+
continue;
|
|
6290
|
+
}
|
|
6291
|
+
styleStr += `${attName}:${attributes[attName]}; `;
|
|
6292
|
+
}
|
|
6293
|
+
return styleStr;
|
|
6285
6294
|
}
|
|
6286
6295
|
function getElementMargins(el) {
|
|
6287
6296
|
const style = window.getComputedStyle(el);
|
|
@@ -7380,7 +7389,7 @@
|
|
|
7380
7389
|
while (!chars.isOver()) {
|
|
7381
7390
|
let token = tokenizeSpace(chars) ||
|
|
7382
7391
|
tokenizeArgsSeparator(chars, locale) ||
|
|
7383
|
-
|
|
7392
|
+
tokenizeParenthesis(chars) ||
|
|
7384
7393
|
tokenizeOperator(chars) ||
|
|
7385
7394
|
tokenizeString(chars) ||
|
|
7386
7395
|
tokenizeDebugger(chars) ||
|
|
@@ -7401,15 +7410,14 @@
|
|
|
7401
7410
|
}
|
|
7402
7411
|
return null;
|
|
7403
7412
|
}
|
|
7404
|
-
const
|
|
7405
|
-
"(": "LEFT_PAREN",
|
|
7406
|
-
")": "RIGHT_PAREN",
|
|
7413
|
+
const parenthesis = {
|
|
7414
|
+
"(": { type: "LEFT_PAREN", value: "(" },
|
|
7415
|
+
")": { type: "RIGHT_PAREN", value: ")" },
|
|
7407
7416
|
};
|
|
7408
|
-
function
|
|
7409
|
-
if (chars.current
|
|
7417
|
+
function tokenizeParenthesis(chars) {
|
|
7418
|
+
if (chars.current === "(" || chars.current === ")") {
|
|
7410
7419
|
const value = chars.shift();
|
|
7411
|
-
|
|
7412
|
-
return { type, value };
|
|
7420
|
+
return parenthesis[value];
|
|
7413
7421
|
}
|
|
7414
7422
|
return null;
|
|
7415
7423
|
}
|
|
@@ -7430,7 +7438,12 @@
|
|
|
7430
7438
|
}
|
|
7431
7439
|
return null;
|
|
7432
7440
|
}
|
|
7441
|
+
const FIRST_POSSIBLE_NUMBER_CHARS = new Set("0123456789");
|
|
7433
7442
|
function tokenizeNumber(chars, locale) {
|
|
7443
|
+
if (!FIRST_POSSIBLE_NUMBER_CHARS.has(chars.current) &&
|
|
7444
|
+
chars.current !== locale.decimalSeparator) {
|
|
7445
|
+
return null;
|
|
7446
|
+
}
|
|
7434
7447
|
const match = chars.remaining().match(getFormulaNumberRegex(locale.decimalSeparator));
|
|
7435
7448
|
if (match) {
|
|
7436
7449
|
chars.advanceBy(match[0].length);
|
|
@@ -7455,7 +7468,7 @@
|
|
|
7455
7468
|
}
|
|
7456
7469
|
return null;
|
|
7457
7470
|
}
|
|
7458
|
-
const separatorRegexp =
|
|
7471
|
+
const separatorRegexp = /^[\w\.!\$]+/;
|
|
7459
7472
|
/**
|
|
7460
7473
|
* A "Symbol" is just basically any word-like element that can appear in a
|
|
7461
7474
|
* formula, which is not a string. So:
|
|
@@ -7495,8 +7508,11 @@
|
|
|
7495
7508
|
};
|
|
7496
7509
|
}
|
|
7497
7510
|
}
|
|
7498
|
-
|
|
7499
|
-
|
|
7511
|
+
const match = chars.remaining().match(separatorRegexp);
|
|
7512
|
+
if (match) {
|
|
7513
|
+
const value = match[0];
|
|
7514
|
+
result += value;
|
|
7515
|
+
chars.advanceBy(value.length);
|
|
7500
7516
|
}
|
|
7501
7517
|
if (result.length) {
|
|
7502
7518
|
const value = result;
|
|
@@ -7558,7 +7574,10 @@
|
|
|
7558
7574
|
return this.text.substring(this.currentIndex);
|
|
7559
7575
|
}
|
|
7560
7576
|
currentStartsWith(str) {
|
|
7561
|
-
|
|
7577
|
+
if (this.current !== str[0]) {
|
|
7578
|
+
return false;
|
|
7579
|
+
}
|
|
7580
|
+
for (let j = 1; j < str.length; j++) {
|
|
7562
7581
|
if (this.text[this.currentIndex + j] !== str[j]) {
|
|
7563
7582
|
return false;
|
|
7564
7583
|
}
|
|
@@ -7585,6 +7604,9 @@
|
|
|
7585
7604
|
if (locale.formulaArgSeparator === locale.decimalSeparator) {
|
|
7586
7605
|
return false;
|
|
7587
7606
|
}
|
|
7607
|
+
if (locale.thousandsSeparator === locale.decimalSeparator) {
|
|
7608
|
+
return false;
|
|
7609
|
+
}
|
|
7588
7610
|
try {
|
|
7589
7611
|
formatValue(1, { locale, format: "#,##0.00" });
|
|
7590
7612
|
formatValue(1, { locale, format: locale.dateFormat });
|
|
@@ -7675,7 +7697,7 @@
|
|
|
7675
7697
|
if (locale.decimalSeparator === "." || !isNumber(content, locale)) {
|
|
7676
7698
|
return content;
|
|
7677
7699
|
}
|
|
7678
|
-
return content.replace(locale.decimalSeparator, ".");
|
|
7700
|
+
return content.replace(locale.thousandsSeparator, "").replace(locale.decimalSeparator, ".");
|
|
7679
7701
|
}
|
|
7680
7702
|
/**
|
|
7681
7703
|
* Change a content string from the given locale to its canonical form (en_US locale). Also convert date string.
|
|
@@ -10747,6 +10769,12 @@
|
|
|
10747
10769
|
let { col, row } = env.model.getters.getActivePosition();
|
|
10748
10770
|
env.model.dispatch("OPEN_CELL_POPOVER", { col, row, popoverType: "LinkEditor" });
|
|
10749
10771
|
};
|
|
10772
|
+
const INSERT_LINK_NAME = (env) => {
|
|
10773
|
+
const sheetId = env.model.getters.getActiveSheetId();
|
|
10774
|
+
const { col, row } = env.model.getters.getActivePosition();
|
|
10775
|
+
const cell = env.model.getters.getEvaluatedCell({ sheetId, col, row });
|
|
10776
|
+
return cell && cell.link ? _t("Edit link") : _t("Insert link");
|
|
10777
|
+
};
|
|
10750
10778
|
//------------------------------------------------------------------------------
|
|
10751
10779
|
// Filters action
|
|
10752
10780
|
//------------------------------------------------------------------------------
|
|
@@ -12899,6 +12927,18 @@
|
|
|
12899
12927
|
},
|
|
12900
12928
|
isExported: true,
|
|
12901
12929
|
};
|
|
12930
|
+
// -----------------------------------------------------------------------------
|
|
12931
|
+
// INT
|
|
12932
|
+
// -----------------------------------------------------------------------------
|
|
12933
|
+
const INT = {
|
|
12934
|
+
description: _t("Rounds a number down to the nearest integer that is less than or equal to it."),
|
|
12935
|
+
args: [arg("value (number)", _t("The number to round down to the nearest integer."))],
|
|
12936
|
+
returns: ["NUMBER"],
|
|
12937
|
+
compute: function (value) {
|
|
12938
|
+
return Math.floor(toNumber(value, this.locale));
|
|
12939
|
+
},
|
|
12940
|
+
isExported: true,
|
|
12941
|
+
};
|
|
12902
12942
|
|
|
12903
12943
|
var math = /*#__PURE__*/Object.freeze({
|
|
12904
12944
|
__proto__: null,
|
|
@@ -12932,6 +12972,7 @@
|
|
|
12932
12972
|
FLOOR: FLOOR,
|
|
12933
12973
|
FLOOR_MATH: FLOOR_MATH,
|
|
12934
12974
|
FLOOR_PRECISE: FLOOR_PRECISE,
|
|
12975
|
+
INT: INT,
|
|
12935
12976
|
ISEVEN: ISEVEN,
|
|
12936
12977
|
ISODD: ISODD,
|
|
12937
12978
|
ISO_CEILING: ISO_CEILING,
|
|
@@ -19778,7 +19819,7 @@
|
|
|
19778
19819
|
})
|
|
19779
19820
|
.add("insert_link", {
|
|
19780
19821
|
...insertLink,
|
|
19781
|
-
name:
|
|
19822
|
+
name: INSERT_LINK_NAME,
|
|
19782
19823
|
sequence: 150,
|
|
19783
19824
|
separator: true,
|
|
19784
19825
|
});
|
|
@@ -21370,7 +21411,7 @@
|
|
|
21370
21411
|
? existingSelectionRanges
|
|
21371
21412
|
: this.props.ranges().map((xc, id) => ({
|
|
21372
21413
|
xc,
|
|
21373
|
-
id,
|
|
21414
|
+
id: id + 1,
|
|
21374
21415
|
isFocused: false,
|
|
21375
21416
|
}));
|
|
21376
21417
|
return ranges.map((range) => ({
|
|
@@ -26031,6 +26072,17 @@
|
|
|
26031
26072
|
`;
|
|
26032
26073
|
class TextValueProvider extends owl.Component {
|
|
26033
26074
|
static template = "o-spreadsheet-TextValueProvider";
|
|
26075
|
+
autoCompleteListRef = owl.useRef("autoCompleteList");
|
|
26076
|
+
setup() {
|
|
26077
|
+
owl.useEffect(() => {
|
|
26078
|
+
const selectedIndex = this.props.selectedIndex;
|
|
26079
|
+
if (selectedIndex === undefined) {
|
|
26080
|
+
return;
|
|
26081
|
+
}
|
|
26082
|
+
const selectedElement = this.autoCompleteListRef.el?.children[selectedIndex];
|
|
26083
|
+
selectedElement?.scrollIntoView?.({ block: "nearest" });
|
|
26084
|
+
}, () => [this.props.selectedIndex, this.autoCompleteListRef.el]);
|
|
26085
|
+
}
|
|
26034
26086
|
}
|
|
26035
26087
|
TextValueProvider.props = {
|
|
26036
26088
|
values: Array,
|
|
@@ -26482,6 +26534,7 @@
|
|
|
26482
26534
|
position: absolute;
|
|
26483
26535
|
margin: 1px 4px;
|
|
26484
26536
|
pointer-events: none;
|
|
26537
|
+
overflow: auto;
|
|
26485
26538
|
|
|
26486
26539
|
.o-semi-bold {
|
|
26487
26540
|
/** FIXME: to remove in favor of Bootstrap
|
|
@@ -26497,6 +26550,7 @@
|
|
|
26497
26550
|
static components = { TextValueProvider, FunctionDescriptionProvider };
|
|
26498
26551
|
static defaultProps = {
|
|
26499
26552
|
inputStyle: "",
|
|
26553
|
+
isDefaultFocus: false,
|
|
26500
26554
|
};
|
|
26501
26555
|
composerRef = owl.useRef("o_composer");
|
|
26502
26556
|
contentHelper = new ContentEditableHelper(this.composerRef.el);
|
|
@@ -26527,7 +26581,10 @@
|
|
|
26527
26581
|
if (this.props.delimitation && this.props.rect) {
|
|
26528
26582
|
const { x: cellX, y: cellY, height: cellHeight } = this.props.rect;
|
|
26529
26583
|
const remainingHeight = this.props.delimitation.height - (cellY + cellHeight);
|
|
26584
|
+
assistantStyle["max-height"] = `${remainingHeight}px`;
|
|
26530
26585
|
if (cellY > remainingHeight) {
|
|
26586
|
+
const availableSpaceAbove = cellY;
|
|
26587
|
+
assistantStyle["max-height"] = `${availableSpaceAbove}px`;
|
|
26531
26588
|
// render top
|
|
26532
26589
|
// We compensate 2 px of margin on the assistant style + 1px for design reasons
|
|
26533
26590
|
assistantStyle.top = `-3px`;
|
|
@@ -26553,7 +26610,6 @@
|
|
|
26553
26610
|
F2: () => console.warn("Not implemented"),
|
|
26554
26611
|
F4: this.processF4Key,
|
|
26555
26612
|
Tab: (ev) => this.processTabKey(ev),
|
|
26556
|
-
" ": (ev) => this.processSpaceKey(ev),
|
|
26557
26613
|
};
|
|
26558
26614
|
keyCodeMapping = {
|
|
26559
26615
|
NumpadDecimal: this.processNumpadDecimal,
|
|
@@ -26561,12 +26617,12 @@
|
|
|
26561
26617
|
setup() {
|
|
26562
26618
|
owl.onMounted(() => {
|
|
26563
26619
|
const el = this.composerRef.el;
|
|
26620
|
+
if (this.props.isDefaultFocus) {
|
|
26621
|
+
this.env.focusableElement.setFocusableElement(el);
|
|
26622
|
+
}
|
|
26564
26623
|
this.contentHelper.updateEl(el);
|
|
26565
26624
|
this.processTokenAtCursor();
|
|
26566
26625
|
});
|
|
26567
|
-
owl.onWillUnmount(() => {
|
|
26568
|
-
this.props.onComposerUnmounted?.();
|
|
26569
|
-
});
|
|
26570
26626
|
owl.useEffect(() => {
|
|
26571
26627
|
this.processContent();
|
|
26572
26628
|
});
|
|
@@ -26575,7 +26631,8 @@
|
|
|
26575
26631
|
// Handlers
|
|
26576
26632
|
// ---------------------------------------------------------------------------
|
|
26577
26633
|
processArrowKeys(ev) {
|
|
26578
|
-
if (this.env.model.getters.isSelectingForComposer()
|
|
26634
|
+
if (this.env.model.getters.isSelectingForComposer() ||
|
|
26635
|
+
this.env.model.getters.getEditionMode() === "inactive") {
|
|
26579
26636
|
this.functionDescriptionState.showDescription = false;
|
|
26580
26637
|
// Prevent the default content editable behavior which moves the cursor
|
|
26581
26638
|
ev.preventDefault();
|
|
@@ -26618,26 +26675,20 @@
|
|
|
26618
26675
|
processTabKey(ev) {
|
|
26619
26676
|
ev.preventDefault();
|
|
26620
26677
|
ev.stopPropagation();
|
|
26621
|
-
|
|
26622
|
-
|
|
26623
|
-
|
|
26624
|
-
|
|
26625
|
-
|
|
26626
|
-
|
|
26678
|
+
if (this.env.model.getters.getEditionMode() !== "inactive") {
|
|
26679
|
+
const state = this.autoCompleteState;
|
|
26680
|
+
if (state.showProvider && state.selectedIndex !== undefined) {
|
|
26681
|
+
const autoCompleteValue = this.autoCompleteState.values[state.selectedIndex]?.text;
|
|
26682
|
+
if (autoCompleteValue) {
|
|
26683
|
+
this.autoComplete(autoCompleteValue);
|
|
26684
|
+
return;
|
|
26685
|
+
}
|
|
26627
26686
|
}
|
|
26687
|
+
interactiveStopEdition(this.env);
|
|
26628
26688
|
}
|
|
26629
26689
|
const direction = ev.shiftKey ? "left" : "right";
|
|
26630
|
-
interactiveStopEdition(this.env);
|
|
26631
26690
|
this.env.model.selection.moveAnchorCell(direction, 1);
|
|
26632
26691
|
}
|
|
26633
|
-
processSpaceKey(ev) {
|
|
26634
|
-
if (ev.ctrlKey) {
|
|
26635
|
-
ev.preventDefault();
|
|
26636
|
-
ev.stopPropagation();
|
|
26637
|
-
this.showFunctionAutocomplete("");
|
|
26638
|
-
this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
|
|
26639
|
-
}
|
|
26640
|
-
}
|
|
26641
26692
|
processEnterKey(ev) {
|
|
26642
26693
|
ev.preventDefault();
|
|
26643
26694
|
ev.stopPropagation();
|
|
@@ -26690,6 +26741,9 @@
|
|
|
26690
26741
|
this.compositionActive = false;
|
|
26691
26742
|
}
|
|
26692
26743
|
onKeydown(ev) {
|
|
26744
|
+
if (this.env.model.getters.getEditionMode() === "inactive") {
|
|
26745
|
+
return;
|
|
26746
|
+
}
|
|
26693
26747
|
let handler = this.keyMapping[ev.key] || this.keyCodeMapping[ev.code];
|
|
26694
26748
|
if (handler) {
|
|
26695
26749
|
handler.call(this, ev);
|
|
@@ -26698,14 +26752,33 @@
|
|
|
26698
26752
|
ev.stopPropagation();
|
|
26699
26753
|
}
|
|
26700
26754
|
}
|
|
26755
|
+
onPaste(ev) {
|
|
26756
|
+
if (this.env.model.getters.getEditionMode() !== "inactive") {
|
|
26757
|
+
ev.stopPropagation();
|
|
26758
|
+
}
|
|
26759
|
+
}
|
|
26701
26760
|
/*
|
|
26702
26761
|
* Triggered automatically by the content-editable between the keydown and key up
|
|
26703
26762
|
* */
|
|
26704
26763
|
onInput(ev) {
|
|
26705
|
-
if (
|
|
26764
|
+
if (!this.shouldProcessInputEvents) {
|
|
26765
|
+
return;
|
|
26766
|
+
}
|
|
26767
|
+
if (ev.inputType === "insertFromPaste" &&
|
|
26768
|
+
this.env.model.getters.getEditionMode() === "inactive") {
|
|
26706
26769
|
return;
|
|
26707
26770
|
}
|
|
26708
|
-
|
|
26771
|
+
ev.stopPropagation();
|
|
26772
|
+
let content;
|
|
26773
|
+
if (this.env.model.getters.getEditionMode() === "inactive") {
|
|
26774
|
+
content = ev.data || "";
|
|
26775
|
+
}
|
|
26776
|
+
else {
|
|
26777
|
+
content = this.contentHelper.getText();
|
|
26778
|
+
}
|
|
26779
|
+
if (this.props.focus === "inactive") {
|
|
26780
|
+
return this.props.onComposerCellFocused?.(content);
|
|
26781
|
+
}
|
|
26709
26782
|
let selection = this.contentHelper.getCurrentSelection();
|
|
26710
26783
|
if (ev.inputType === "insertParagraph") {
|
|
26711
26784
|
const start = Math.min(selection.start, selection.end);
|
|
@@ -26787,9 +26860,8 @@
|
|
|
26787
26860
|
}
|
|
26788
26861
|
const newSelection = this.contentHelper.getCurrentSelection();
|
|
26789
26862
|
this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
|
|
26790
|
-
|
|
26791
|
-
|
|
26792
|
-
}
|
|
26863
|
+
this.props.onComposerContentFocused();
|
|
26864
|
+
if (this.props.focus === "inactive") ;
|
|
26793
26865
|
this.env.model.dispatch("CHANGE_COMPOSER_CURSOR_SELECTION", newSelection);
|
|
26794
26866
|
this.processTokenAtCursor();
|
|
26795
26867
|
}
|
|
@@ -26956,7 +27028,7 @@
|
|
|
26956
27028
|
const highlights = this.env.model.getters.getHighlights();
|
|
26957
27029
|
const refSheet = sheetName
|
|
26958
27030
|
? this.env.model.getters.getSheetIdByName(sheetName)
|
|
26959
|
-
: this.env.model.getters.getCurrentEditedCell()
|
|
27031
|
+
: this.env.model.getters.getCurrentEditedCell()?.sheetId;
|
|
26960
27032
|
const highlight = highlights.find((highlight) => {
|
|
26961
27033
|
if (highlight.sheetId !== refSheet)
|
|
26962
27034
|
return false;
|
|
@@ -27049,12 +27121,13 @@
|
|
|
27049
27121
|
}
|
|
27050
27122
|
}
|
|
27051
27123
|
Composer.props = {
|
|
27052
|
-
focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
|
|
27053
|
-
onComposerContentFocused: Function,
|
|
27054
27124
|
inputStyle: { type: String, optional: true },
|
|
27055
27125
|
rect: { type: Object, optional: true },
|
|
27056
27126
|
delimitation: { type: Object, optional: true },
|
|
27057
|
-
|
|
27127
|
+
focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
|
|
27128
|
+
onComposerCellFocused: { type: Function, optional: true },
|
|
27129
|
+
onComposerContentFocused: Function,
|
|
27130
|
+
isDefaultFocus: { type: Boolean, optional: true },
|
|
27058
27131
|
};
|
|
27059
27132
|
|
|
27060
27133
|
const COMPOSER_BORDER_WIDTH = 3 * 0.4 * window.devicePixelRatio || 1;
|
|
@@ -27088,51 +27161,25 @@
|
|
|
27088
27161
|
class GridComposer extends owl.Component {
|
|
27089
27162
|
static template = "o-spreadsheet-GridComposer";
|
|
27090
27163
|
static components = { Composer };
|
|
27091
|
-
|
|
27092
|
-
|
|
27093
|
-
rect;
|
|
27164
|
+
rect = this.defaultRect;
|
|
27165
|
+
isEditing = false;
|
|
27094
27166
|
isCellReferenceVisible;
|
|
27095
|
-
|
|
27167
|
+
get defaultRect() {
|
|
27168
|
+
return { x: 0, y: 0, width: 0, height: 0 };
|
|
27169
|
+
}
|
|
27096
27170
|
setup() {
|
|
27097
|
-
this.gridComposerRef = owl.useRef("gridComposer");
|
|
27098
|
-
this.composerState = owl.useState({
|
|
27099
|
-
rect: undefined,
|
|
27100
|
-
delimitation: undefined,
|
|
27101
|
-
});
|
|
27102
|
-
const { sheetId, col, row } = this.env.model.getters.getActivePosition();
|
|
27103
|
-
this.zone = this.env.model.getters.expandZone(sheetId, positionToZone({ col, row }));
|
|
27104
|
-
this.rect = this.env.model.getters.getVisibleRect(this.zone);
|
|
27105
|
-
this.isCellReferenceVisible = false;
|
|
27106
|
-
owl.onMounted(() => {
|
|
27107
|
-
const el = this.gridComposerRef.el;
|
|
27108
|
-
this.composerState.rect = {
|
|
27109
|
-
x: this.rect.x,
|
|
27110
|
-
y: this.rect.y,
|
|
27111
|
-
width: el.clientWidth,
|
|
27112
|
-
height: el.clientHeight,
|
|
27113
|
-
};
|
|
27114
|
-
this.composerState.delimitation = {
|
|
27115
|
-
width: this.props.gridDims.width,
|
|
27116
|
-
height: this.props.gridDims.height,
|
|
27117
|
-
};
|
|
27118
|
-
});
|
|
27119
27171
|
owl.onWillUpdateProps(() => {
|
|
27120
|
-
|
|
27121
|
-
|
|
27122
|
-
}
|
|
27123
|
-
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
27124
|
-
const zone = this.env.model.getters.getSelectedZone();
|
|
27125
|
-
const rect = this.env.model.getters.getVisibleRect(zone);
|
|
27126
|
-
if (!deepEquals(rect, this.rect) ||
|
|
27127
|
-
sheetId !== this.env.model.getters.getCurrentEditedCell().sheetId) {
|
|
27128
|
-
this.isCellReferenceVisible = true;
|
|
27129
|
-
}
|
|
27172
|
+
this.updateComponentPosition();
|
|
27173
|
+
this.updateCellReferenceVisibility();
|
|
27130
27174
|
});
|
|
27131
27175
|
}
|
|
27132
27176
|
get shouldDisplayCellReference() {
|
|
27133
27177
|
return this.isCellReferenceVisible;
|
|
27134
27178
|
}
|
|
27135
27179
|
get cellReference() {
|
|
27180
|
+
if (!this.env.model.getters.getCurrentEditedCell()) {
|
|
27181
|
+
return "";
|
|
27182
|
+
}
|
|
27136
27183
|
const { col, row, sheetId } = this.env.model.getters.getCurrentEditedCell();
|
|
27137
27184
|
const prefixSheet = sheetId !== this.env.model.getters.getActiveSheetId();
|
|
27138
27185
|
return `${prefixSheet ? getCanonicalSheetName(this.env.model.getters.getSheetName(sheetId)) + "!" : ""}${toXC(col, row)}`;
|
|
@@ -27144,7 +27191,27 @@
|
|
|
27144
27191
|
top: `${top - GRID_CELL_REFERENCE_TOP_OFFSET}px`,
|
|
27145
27192
|
});
|
|
27146
27193
|
}
|
|
27194
|
+
get composerProps() {
|
|
27195
|
+
const { width, height } = this.env.model.getters.getSheetViewDimensionWithHeaders();
|
|
27196
|
+
return {
|
|
27197
|
+
rect: { ...this.rect },
|
|
27198
|
+
delimitation: {
|
|
27199
|
+
width,
|
|
27200
|
+
height,
|
|
27201
|
+
},
|
|
27202
|
+
focus: this.props.focus,
|
|
27203
|
+
isDefaultFocus: true,
|
|
27204
|
+
onComposerContentFocused: this.props.onComposerContentFocused,
|
|
27205
|
+
onComposerCellFocused: this.props.onComposerCellFocused,
|
|
27206
|
+
};
|
|
27207
|
+
}
|
|
27147
27208
|
get containerStyle() {
|
|
27209
|
+
if (this.env.model.getters.getEditionMode() === "inactive" || !this.rect) {
|
|
27210
|
+
return `
|
|
27211
|
+
position: absolute;
|
|
27212
|
+
z-index: -1000;
|
|
27213
|
+
`;
|
|
27214
|
+
}
|
|
27148
27215
|
const isFormula = this.env.model.getters.getCurrentContent().startsWith("=");
|
|
27149
27216
|
const cell = this.env.model.getters.getActiveCell();
|
|
27150
27217
|
const position = this.env.model.getters.getActivePosition();
|
|
@@ -27164,6 +27231,8 @@
|
|
|
27164
27231
|
if (!isFormula) {
|
|
27165
27232
|
textAlign = style.align || cell.defaultAlign;
|
|
27166
27233
|
}
|
|
27234
|
+
const maxHeight = this.props.gridDims.height - this.rect.y;
|
|
27235
|
+
const maxWidth = this.props.gridDims.width - this.rect.x;
|
|
27167
27236
|
/**
|
|
27168
27237
|
* min-size is on the container, not the composer element, because we want to have the same size as the cell by default,
|
|
27169
27238
|
* including all the paddings/margins of the composer
|
|
@@ -27175,6 +27244,8 @@
|
|
|
27175
27244
|
top: `${top}px`,
|
|
27176
27245
|
"min-width": `${width + 1}px`,
|
|
27177
27246
|
"min-height": `${height + 1}px`,
|
|
27247
|
+
"max-width": `${maxWidth}px`,
|
|
27248
|
+
"max-height": `${maxHeight}px`,
|
|
27178
27249
|
background,
|
|
27179
27250
|
color,
|
|
27180
27251
|
"font-size": `${fontSizeInPixels(fontSize)}px`,
|
|
@@ -27184,20 +27255,38 @@
|
|
|
27184
27255
|
"text-align": textAlign,
|
|
27185
27256
|
});
|
|
27186
27257
|
}
|
|
27187
|
-
|
|
27188
|
-
const
|
|
27189
|
-
|
|
27190
|
-
|
|
27191
|
-
|
|
27192
|
-
|
|
27193
|
-
|
|
27258
|
+
updateComponentPosition() {
|
|
27259
|
+
const isEditing = this.env.model.getters.getEditionMode() !== "inactive";
|
|
27260
|
+
if (this.isEditing !== isEditing) {
|
|
27261
|
+
this.isEditing = isEditing;
|
|
27262
|
+
if (!isEditing) {
|
|
27263
|
+
this.rect = this.defaultRect;
|
|
27264
|
+
this.env.focusableElement.focus();
|
|
27265
|
+
return;
|
|
27266
|
+
}
|
|
27267
|
+
const position = this.env.model.getters.getActivePosition();
|
|
27268
|
+
const zone = this.env.model.getters.expandZone(position.sheetId, positionToZone(position));
|
|
27269
|
+
this.rect = this.env.model.getters.getVisibleRect(zone);
|
|
27270
|
+
}
|
|
27271
|
+
}
|
|
27272
|
+
updateCellReferenceVisibility() {
|
|
27273
|
+
if (this.isCellReferenceVisible || this.env.model.getters.getEditionMode() === "inactive") {
|
|
27274
|
+
return;
|
|
27275
|
+
}
|
|
27276
|
+
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
27277
|
+
const zone = this.env.model.getters.getSelectedZone();
|
|
27278
|
+
const rect = this.env.model.getters.getVisibleRect(zone);
|
|
27279
|
+
if (!deepEquals(rect, this.rect) ||
|
|
27280
|
+
sheetId !== this.env.model.getters.getCurrentEditedCell().sheetId) {
|
|
27281
|
+
this.isCellReferenceVisible = true;
|
|
27282
|
+
}
|
|
27194
27283
|
}
|
|
27195
27284
|
}
|
|
27196
27285
|
GridComposer.props = {
|
|
27197
27286
|
focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
|
|
27198
|
-
onComposerUnmounted: Function,
|
|
27199
27287
|
onComposerContentFocused: Function,
|
|
27200
27288
|
gridDims: Object,
|
|
27289
|
+
onComposerCellFocused: Function,
|
|
27201
27290
|
};
|
|
27202
27291
|
|
|
27203
27292
|
const CSS$1 = css /* scss */ `
|
|
@@ -28288,7 +28377,6 @@
|
|
|
28288
28377
|
this.props.onCellDoubleClicked(col, row);
|
|
28289
28378
|
}
|
|
28290
28379
|
onContextMenu(ev) {
|
|
28291
|
-
ev.preventDefault();
|
|
28292
28380
|
const [col, row] = this.getCartesianCoordinates(ev);
|
|
28293
28381
|
this.props.onCellRightClicked(col, row, { x: ev.clientX, y: ev.clientY });
|
|
28294
28382
|
}
|
|
@@ -29373,7 +29461,6 @@
|
|
|
29373
29461
|
HEADER_WIDTH = HEADER_WIDTH;
|
|
29374
29462
|
menuState;
|
|
29375
29463
|
gridRef;
|
|
29376
|
-
hiddenInput;
|
|
29377
29464
|
onMouseWheel;
|
|
29378
29465
|
canvasPosition;
|
|
29379
29466
|
hoveredCell;
|
|
@@ -29384,17 +29471,16 @@
|
|
|
29384
29471
|
menuItems: [],
|
|
29385
29472
|
});
|
|
29386
29473
|
this.gridRef = owl.useRef("grid");
|
|
29387
|
-
this.hiddenInput = owl.useRef("hiddenInput");
|
|
29388
29474
|
this.canvasPosition = useAbsoluteBoundingRect(this.gridRef);
|
|
29389
29475
|
this.hoveredCell = owl.useState({ col: undefined, row: undefined });
|
|
29390
29476
|
owl.useChildSubEnv({ getPopoverContainerRect: () => this.getGridRect() });
|
|
29391
29477
|
owl.useExternalListener(document.body, "cut", this.copy.bind(this, true));
|
|
29392
29478
|
owl.useExternalListener(document.body, "copy", this.copy.bind(this, false));
|
|
29393
29479
|
owl.useExternalListener(document.body, "paste", this.paste);
|
|
29394
|
-
owl.onMounted(() => this.
|
|
29395
|
-
this.props.exposeFocus(() => this.
|
|
29480
|
+
owl.onMounted(() => this.focusDefaultElement());
|
|
29481
|
+
this.props.exposeFocus(() => this.focusDefaultElement());
|
|
29396
29482
|
useGridDrawing("canvas", this.env.model, () => this.env.model.getters.getSheetViewDimensionWithHeaders());
|
|
29397
|
-
owl.useEffect(() => this.
|
|
29483
|
+
owl.useEffect(() => this.focusDefaultElement(), () => [this.env.model.getters.getActiveSheetId()]);
|
|
29398
29484
|
this.onMouseWheel = useWheelHandler((deltaX, deltaY) => {
|
|
29399
29485
|
this.moveCanvas(deltaX, deltaY);
|
|
29400
29486
|
this.hoveredCell.col = undefined;
|
|
@@ -29417,7 +29503,7 @@
|
|
|
29417
29503
|
if (this.env.model.getters.hasOpenedPopover()) {
|
|
29418
29504
|
this.closeOpenedPopover();
|
|
29419
29505
|
}
|
|
29420
|
-
this.
|
|
29506
|
+
this.focusDefaultElement();
|
|
29421
29507
|
}
|
|
29422
29508
|
// this map will handle most of the actions that should happen on key down. The arrow keys are managed in the key
|
|
29423
29509
|
// down itself
|
|
@@ -29596,10 +29682,10 @@
|
|
|
29596
29682
|
"ALT+SHIFT+ARROWUP": () => this.processHeaderGroupingKey("up"),
|
|
29597
29683
|
"ALT+SHIFT+ARROWDOWN": () => this.processHeaderGroupingKey("down"),
|
|
29598
29684
|
};
|
|
29599
|
-
|
|
29685
|
+
focusDefaultElement() {
|
|
29600
29686
|
if (!this.env.model.getters.getSelectedFigureId() &&
|
|
29601
29687
|
this.env.model.getters.getEditionMode() === "inactive") {
|
|
29602
|
-
this.
|
|
29688
|
+
this.env.focusableElement.focus();
|
|
29603
29689
|
}
|
|
29604
29690
|
}
|
|
29605
29691
|
get gridEl() {
|
|
@@ -29744,19 +29830,6 @@
|
|
|
29744
29830
|
return;
|
|
29745
29831
|
}
|
|
29746
29832
|
}
|
|
29747
|
-
onInput(ev) {
|
|
29748
|
-
// the user meant to paste in the sheet, not open the composer with the pasted content
|
|
29749
|
-
if (!ev.isComposing && ev.inputType === "insertFromPaste") {
|
|
29750
|
-
return;
|
|
29751
|
-
}
|
|
29752
|
-
if (ev.data) {
|
|
29753
|
-
// if the user types a character on the grid, it means he wants to start composing the selected cell with that
|
|
29754
|
-
// character
|
|
29755
|
-
ev.preventDefault();
|
|
29756
|
-
ev.stopPropagation();
|
|
29757
|
-
this.props.onGridComposerCellFocused(ev.data);
|
|
29758
|
-
}
|
|
29759
|
-
}
|
|
29760
29833
|
// ---------------------------------------------------------------------------
|
|
29761
29834
|
// Context Menu
|
|
29762
29835
|
// ---------------------------------------------------------------------------
|
|
@@ -29871,7 +29944,7 @@
|
|
|
29871
29944
|
}
|
|
29872
29945
|
closeMenu() {
|
|
29873
29946
|
this.menuState.isOpen = false;
|
|
29874
|
-
this.
|
|
29947
|
+
this.focusDefaultElement();
|
|
29875
29948
|
}
|
|
29876
29949
|
processHeaderGroupingKey(direction) {
|
|
29877
29950
|
if (this.env.model.getters.getSelectedZones().length !== 1) {
|
|
@@ -33767,8 +33840,16 @@
|
|
|
33767
33840
|
},
|
|
33768
33841
|
},
|
|
33769
33842
|
{
|
|
33770
|
-
description: "
|
|
33843
|
+
description: "Fix datafilter duplication",
|
|
33771
33844
|
from: 12,
|
|
33845
|
+
to: 12.5,
|
|
33846
|
+
applyMigration(data) {
|
|
33847
|
+
return fixOverlappingFilters(data);
|
|
33848
|
+
},
|
|
33849
|
+
},
|
|
33850
|
+
{
|
|
33851
|
+
description: "Change Border description structure",
|
|
33852
|
+
from: 12.5,
|
|
33772
33853
|
to: 13,
|
|
33773
33854
|
applyMigration(data) {
|
|
33774
33855
|
for (const borderId in data.borders) {
|
|
@@ -33799,6 +33880,14 @@
|
|
|
33799
33880
|
return data;
|
|
33800
33881
|
},
|
|
33801
33882
|
},
|
|
33883
|
+
{
|
|
33884
|
+
description: "Fix datafilter duplication (post saas-16.4)",
|
|
33885
|
+
from: 14,
|
|
33886
|
+
to: 14.5,
|
|
33887
|
+
applyMigration(data) {
|
|
33888
|
+
return fixOverlappingFilters(data);
|
|
33889
|
+
},
|
|
33890
|
+
},
|
|
33802
33891
|
];
|
|
33803
33892
|
/**
|
|
33804
33893
|
* This function is used to repair faulty data independently of the migration.
|
|
@@ -33956,6 +34045,26 @@
|
|
|
33956
34045
|
}
|
|
33957
34046
|
return messages;
|
|
33958
34047
|
}
|
|
34048
|
+
function fixOverlappingFilters(data) {
|
|
34049
|
+
for (let sheet of data.sheets || []) {
|
|
34050
|
+
let knownDataFilterZones = [];
|
|
34051
|
+
for (let filterTable of sheet.filterTables || []) {
|
|
34052
|
+
const zone = toZone(filterTable.range);
|
|
34053
|
+
// See commit message of https://github.com/odoo/o-spreadsheet/pull/3632 of more details
|
|
34054
|
+
const intersectZoneIndex = knownDataFilterZones.findIndex((knownZone) => overlap(knownZone, zone));
|
|
34055
|
+
if (intersectZoneIndex !== -1) {
|
|
34056
|
+
knownDataFilterZones[intersectZoneIndex] = zone;
|
|
34057
|
+
}
|
|
34058
|
+
else {
|
|
34059
|
+
knownDataFilterZones.push(zone);
|
|
34060
|
+
}
|
|
34061
|
+
}
|
|
34062
|
+
sheet.filterTables = knownDataFilterZones.map((zone) => ({
|
|
34063
|
+
range: zoneToXc(zone),
|
|
34064
|
+
}));
|
|
34065
|
+
}
|
|
34066
|
+
return data;
|
|
34067
|
+
}
|
|
33959
34068
|
// -----------------------------------------------------------------------------
|
|
33960
34069
|
// Helpers
|
|
33961
34070
|
// -----------------------------------------------------------------------------
|
|
@@ -34605,22 +34714,7 @@
|
|
|
34605
34714
|
}
|
|
34606
34715
|
}
|
|
34607
34716
|
export(data) {
|
|
34608
|
-
// Borders
|
|
34609
|
-
let borderId = 0;
|
|
34610
34717
|
const borders = {};
|
|
34611
|
-
/**
|
|
34612
|
-
* Get the id of the given border. If the border does not exist, it creates
|
|
34613
|
-
* one.
|
|
34614
|
-
*/
|
|
34615
|
-
function getBorderId(border) {
|
|
34616
|
-
for (let [key, value] of Object.entries(borders)) {
|
|
34617
|
-
if (deepEquals(value, border)) {
|
|
34618
|
-
return parseInt(key, 10);
|
|
34619
|
-
}
|
|
34620
|
-
}
|
|
34621
|
-
borders[++borderId] = border;
|
|
34622
|
-
return borderId;
|
|
34623
|
-
}
|
|
34624
34718
|
for (let sheet of data.sheets) {
|
|
34625
34719
|
for (let col = 0; col < sheet.colNumber; col++) {
|
|
34626
34720
|
for (let row = 0; row < sheet.rowNumber; row++) {
|
|
@@ -34628,7 +34722,7 @@
|
|
|
34628
34722
|
if (border) {
|
|
34629
34723
|
const xc = toXC(col, row);
|
|
34630
34724
|
const cell = sheet.cells[xc];
|
|
34631
|
-
const borderId =
|
|
34725
|
+
const borderId = getItemId(border, borders);
|
|
34632
34726
|
if (cell) {
|
|
34633
34727
|
cell.border = borderId;
|
|
34634
34728
|
}
|
|
@@ -35433,9 +35527,9 @@
|
|
|
35433
35527
|
allowDispatch(cmd) {
|
|
35434
35528
|
switch (cmd.type) {
|
|
35435
35529
|
case "UPDATE_CELL":
|
|
35436
|
-
return this.
|
|
35530
|
+
return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessUpdateCell);
|
|
35437
35531
|
case "CLEAR_CELL":
|
|
35438
|
-
return this.checkValidations(cmd, this.
|
|
35532
|
+
return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessClearCell);
|
|
35439
35533
|
default:
|
|
35440
35534
|
return "Success" /* CommandResult.Success */;
|
|
35441
35535
|
}
|
|
@@ -35568,9 +35662,6 @@
|
|
|
35568
35662
|
format: cell.format ? getItemId(cell.format, formats) : undefined,
|
|
35569
35663
|
content: cell.content || undefined,
|
|
35570
35664
|
};
|
|
35571
|
-
if (cell instanceof FormulaCellWithDependencies) {
|
|
35572
|
-
cells[xc].content = cell.contentWithFixedReferences || undefined;
|
|
35573
|
-
}
|
|
35574
35665
|
}
|
|
35575
35666
|
_sheet.cells = cells;
|
|
35576
35667
|
}
|
|
@@ -35588,8 +35679,8 @@
|
|
|
35588
35679
|
}
|
|
35589
35680
|
removeDefaultStyleValues(style) {
|
|
35590
35681
|
const cleanedStyle = { ...style };
|
|
35591
|
-
for (const
|
|
35592
|
-
if (cleanedStyle[property] ===
|
|
35682
|
+
for (const property in DEFAULT_STYLE) {
|
|
35683
|
+
if (cleanedStyle[property] === DEFAULT_STYLE[property]) {
|
|
35593
35684
|
delete cleanedStyle[property];
|
|
35594
35685
|
}
|
|
35595
35686
|
}
|
|
@@ -35746,10 +35837,7 @@
|
|
|
35746
35837
|
else {
|
|
35747
35838
|
style = before ? before.style : undefined;
|
|
35748
35839
|
}
|
|
35749
|
-
const
|
|
35750
|
-
let format = ("format" in after ? after.format : before && before.format) ||
|
|
35751
|
-
detectDateFormat(afterContent, locale) ||
|
|
35752
|
-
detectNumberFormat(afterContent);
|
|
35840
|
+
const format = "format" in after ? after.format : before && before.format;
|
|
35753
35841
|
/* Read the following IF as:
|
|
35754
35842
|
* we need to remove the cell if it is completely empty, but we can know if it completely empty if:
|
|
35755
35843
|
* - the command says the new content is empty and has no border/format/style
|
|
@@ -35790,12 +35878,11 @@
|
|
|
35790
35878
|
}
|
|
35791
35879
|
createLiteralCell(id, content, format, style) {
|
|
35792
35880
|
const locale = this.getters.getLocale();
|
|
35793
|
-
content = parseLiteral(content, locale).toString();
|
|
35794
35881
|
return {
|
|
35795
35882
|
id,
|
|
35796
|
-
content,
|
|
35883
|
+
content: parseLiteral(content, locale).toString(),
|
|
35797
35884
|
style,
|
|
35798
|
-
format,
|
|
35885
|
+
format: format || detectDateFormat(content, locale) || detectNumberFormat(content),
|
|
35799
35886
|
isFormula: false,
|
|
35800
35887
|
};
|
|
35801
35888
|
}
|
|
@@ -35821,8 +35908,11 @@
|
|
|
35821
35908
|
* being a computed property to rebuild the dependencies XC.
|
|
35822
35909
|
*/
|
|
35823
35910
|
createFormulaCellWithDependencies(id, compiledFormula, format, style, sheetId) {
|
|
35824
|
-
const dependencies =
|
|
35825
|
-
|
|
35911
|
+
const dependencies = [];
|
|
35912
|
+
for (const xc of compiledFormula.dependencies) {
|
|
35913
|
+
dependencies.push(this.getters.getRangeFromSheetXC(sheetId, xc));
|
|
35914
|
+
}
|
|
35915
|
+
return new FormulaCellWithDependencies(id, compiledFormula, format, style, dependencies, sheetId, this.getters.getRangeString);
|
|
35826
35916
|
}
|
|
35827
35917
|
createErrorFormula(id, content, format, style, error) {
|
|
35828
35918
|
return {
|
|
@@ -35857,6 +35947,18 @@
|
|
|
35857
35947
|
}
|
|
35858
35948
|
return "Success" /* CommandResult.Success */;
|
|
35859
35949
|
}
|
|
35950
|
+
checkUselessUpdateCell(cmd) {
|
|
35951
|
+
const cell = this.getters.getCell(cmd);
|
|
35952
|
+
const hasContent = "content" in cmd || "formula" in cmd;
|
|
35953
|
+
const hasStyle = "style" in cmd;
|
|
35954
|
+
const hasFormat = "format" in cmd;
|
|
35955
|
+
if ((!hasContent || cell?.content === cmd.content) &&
|
|
35956
|
+
(!hasStyle || deepEquals(cell?.style, cmd.style)) &&
|
|
35957
|
+
(!hasFormat || cell?.format === cmd.format)) {
|
|
35958
|
+
return "NoChanges" /* CommandResult.NoChanges */;
|
|
35959
|
+
}
|
|
35960
|
+
return "Success" /* CommandResult.Success */;
|
|
35961
|
+
}
|
|
35860
35962
|
}
|
|
35861
35963
|
class FormulaCellWithDependencies {
|
|
35862
35964
|
id;
|
|
@@ -35876,7 +35978,7 @@
|
|
|
35876
35978
|
const tokens = compiledFormula.tokens.map((token) => {
|
|
35877
35979
|
if (token.type === "REFERENCE") {
|
|
35878
35980
|
const index = rangeIndex++;
|
|
35879
|
-
return new RangeReferenceToken(
|
|
35981
|
+
return new RangeReferenceToken(dependencies, index, this.sheetId, this.getRangeString);
|
|
35880
35982
|
}
|
|
35881
35983
|
return token;
|
|
35882
35984
|
});
|
|
@@ -35903,13 +36005,20 @@
|
|
|
35903
36005
|
}
|
|
35904
36006
|
}
|
|
35905
36007
|
class RangeReferenceToken {
|
|
35906
|
-
|
|
36008
|
+
ranges;
|
|
36009
|
+
rangeIndex;
|
|
36010
|
+
sheetId;
|
|
36011
|
+
getRangeString;
|
|
35907
36012
|
type = "REFERENCE";
|
|
35908
|
-
constructor(
|
|
35909
|
-
this.
|
|
36013
|
+
constructor(ranges, rangeIndex, sheetId, getRangeString) {
|
|
36014
|
+
this.ranges = ranges;
|
|
36015
|
+
this.rangeIndex = rangeIndex;
|
|
36016
|
+
this.sheetId = sheetId;
|
|
36017
|
+
this.getRangeString = getRangeString;
|
|
35910
36018
|
}
|
|
35911
36019
|
get value() {
|
|
35912
|
-
|
|
36020
|
+
const range = this.ranges[this.rangeIndex];
|
|
36021
|
+
return this.getRangeString(range, this.sheetId);
|
|
35913
36022
|
}
|
|
35914
36023
|
}
|
|
35915
36024
|
|
|
@@ -40645,7 +40754,15 @@
|
|
|
40645
40754
|
if (!this.rTrees[sheetId]) {
|
|
40646
40755
|
return;
|
|
40647
40756
|
}
|
|
40648
|
-
this.rTrees[sheetId].remove(item,
|
|
40757
|
+
this.rTrees[sheetId].remove(item, this.rtreeItemComparer);
|
|
40758
|
+
}
|
|
40759
|
+
rtreeItemComparer(left, right) {
|
|
40760
|
+
return (left.data == right.data &&
|
|
40761
|
+
left.boundingBox.sheetId === right.boundingBox.sheetId &&
|
|
40762
|
+
left.boundingBox?.zone.left === right.boundingBox.zone.left &&
|
|
40763
|
+
left.boundingBox?.zone.top === right.boundingBox.zone.top &&
|
|
40764
|
+
left.boundingBox?.zone.right === right.boundingBox.zone.right &&
|
|
40765
|
+
left.boundingBox?.zone.bottom === right.boundingBox.zone.bottom);
|
|
40649
40766
|
}
|
|
40650
40767
|
}
|
|
40651
40768
|
/**
|
|
@@ -40723,7 +40840,7 @@
|
|
|
40723
40840
|
const queue = Array.from(ranges).reverse();
|
|
40724
40841
|
while (queue.length > 0) {
|
|
40725
40842
|
const range = queue.pop();
|
|
40726
|
-
visited.
|
|
40843
|
+
visited.addMany(this.encoder.encodeBoundingBox(range));
|
|
40727
40844
|
const impactedPositionIds = this.rTree.search(range).map((dep) => dep.data);
|
|
40728
40845
|
for (const positionId of impactedPositionIds) {
|
|
40729
40846
|
if (!visited.has(positionId)) {
|
|
@@ -40731,7 +40848,7 @@
|
|
|
40731
40848
|
}
|
|
40732
40849
|
}
|
|
40733
40850
|
}
|
|
40734
|
-
visited.
|
|
40851
|
+
visited.deleteMany(ranges.flatMap((r) => this.encoder.encodeBoundingBox(r)));
|
|
40735
40852
|
return visited;
|
|
40736
40853
|
}
|
|
40737
40854
|
}
|
|
@@ -40869,9 +40986,9 @@
|
|
|
40869
40986
|
const cells = positions.map((p) => this.encoder.encode(p));
|
|
40870
40987
|
const cellsToCompute = new JetSet(cells);
|
|
40871
40988
|
const arrayFormulasPositionIds = this.getArrayFormulasImpactedByChangesOf(cells);
|
|
40872
|
-
cellsToCompute.
|
|
40873
|
-
cellsToCompute.
|
|
40874
|
-
cellsToCompute.
|
|
40989
|
+
cellsToCompute.addMany(this.getCellsDependingOn(cells));
|
|
40990
|
+
cellsToCompute.addMany(arrayFormulasPositionIds);
|
|
40991
|
+
cellsToCompute.addMany(this.getCellsDependingOn(arrayFormulasPositionIds));
|
|
40875
40992
|
this.evaluate(cellsToCompute);
|
|
40876
40993
|
}
|
|
40877
40994
|
getArrayFormulasImpactedByChangesOf(positionIds) {
|
|
@@ -40885,7 +41002,7 @@
|
|
|
40885
41002
|
}
|
|
40886
41003
|
if (!content) {
|
|
40887
41004
|
// The previous content could have blocked some array formulas
|
|
40888
|
-
impactedPositionIds.
|
|
41005
|
+
impactedPositionIds.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(positionId));
|
|
40889
41006
|
}
|
|
40890
41007
|
}
|
|
40891
41008
|
return impactedPositionIds;
|
|
@@ -40934,7 +41051,7 @@
|
|
|
40934
41051
|
}
|
|
40935
41052
|
const arrayFormulas = this.spreadingRelations.getFormulaPositionsSpreadingOn(positionId);
|
|
40936
41053
|
const cells = new JetSet(arrayFormulas);
|
|
40937
|
-
cells.
|
|
41054
|
+
cells.addMany(this.getCellsDependingOn(arrayFormulas));
|
|
40938
41055
|
return cells;
|
|
40939
41056
|
}
|
|
40940
41057
|
nextPositionsToUpdate = new JetSet();
|
|
@@ -41083,7 +41200,7 @@
|
|
|
41083
41200
|
this.setEvaluatedCell(positionId, evaluatedCell);
|
|
41084
41201
|
// check if formula dependencies present in the spread zone
|
|
41085
41202
|
// if so, they need to be recomputed
|
|
41086
|
-
this.nextPositionsToUpdate.
|
|
41203
|
+
this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([positionId]));
|
|
41087
41204
|
};
|
|
41088
41205
|
}
|
|
41089
41206
|
invalidateSpreading(positionId) {
|
|
@@ -41098,8 +41215,8 @@
|
|
|
41098
41215
|
continue;
|
|
41099
41216
|
}
|
|
41100
41217
|
this.evaluatedCells.delete(child);
|
|
41101
|
-
this.nextPositionsToUpdate.
|
|
41102
|
-
this.nextPositionsToUpdate.
|
|
41218
|
+
this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([child]));
|
|
41219
|
+
this.nextPositionsToUpdate.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(child));
|
|
41103
41220
|
}
|
|
41104
41221
|
this.spreadingRelations.removeNode(positionId);
|
|
41105
41222
|
}
|
|
@@ -41448,7 +41565,13 @@
|
|
|
41448
41565
|
const format = newFormat
|
|
41449
41566
|
? getItemId(newFormat, data.formats)
|
|
41450
41567
|
: exportedCellData.format;
|
|
41451
|
-
|
|
41568
|
+
let content;
|
|
41569
|
+
if (formulaCell instanceof FormulaCellWithDependencies) {
|
|
41570
|
+
content = this.getters.getFormulaCellContent(exportedSheetData.id, formulaCell.compiledFormula, formulaCell.compiledFormula.dependencies, true);
|
|
41571
|
+
}
|
|
41572
|
+
else {
|
|
41573
|
+
content = !isExported ? newContent : exportedCellData.content;
|
|
41574
|
+
}
|
|
41452
41575
|
exportedSheetData.cells[xc] = { ...exportedCellData, value, isFormula, content, format };
|
|
41453
41576
|
}
|
|
41454
41577
|
}
|
|
@@ -46332,19 +46455,17 @@
|
|
|
46332
46455
|
break;
|
|
46333
46456
|
case "FOCUS_RANGE":
|
|
46334
46457
|
case "CHANGE_RANGE":
|
|
46335
|
-
|
|
46336
|
-
|
|
46337
|
-
|
|
46338
|
-
|
|
46339
|
-
|
|
46340
|
-
|
|
46341
|
-
|
|
46342
|
-
|
|
46343
|
-
|
|
46344
|
-
});
|
|
46345
|
-
}
|
|
46346
|
-
this.focusedInputId = cmd.id;
|
|
46458
|
+
const input = this.inputs[cmd.id];
|
|
46459
|
+
const range = input.ranges.find((range) => range.id === cmd.rangeId);
|
|
46460
|
+
if (range) {
|
|
46461
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
46462
|
+
const zone = this.getters.getRangeFromSheetXC(sheetId, range?.xc || "A1").zone;
|
|
46463
|
+
this.selection.capture(input, { cell: { col: zone.left, row: zone.top }, zone }, {
|
|
46464
|
+
handleEvent: input.handleEvent.bind(input),
|
|
46465
|
+
release: () => (this.focusedInputId = null),
|
|
46466
|
+
});
|
|
46347
46467
|
}
|
|
46468
|
+
this.focusedInputId = cmd.id;
|
|
46348
46469
|
break;
|
|
46349
46470
|
}
|
|
46350
46471
|
this.currentInput?.handle(cmd);
|
|
@@ -50764,6 +50885,16 @@
|
|
|
50764
50885
|
}
|
|
50765
50886
|
}
|
|
50766
50887
|
|
|
50888
|
+
class FocusableElement {
|
|
50889
|
+
focusableElement = undefined;
|
|
50890
|
+
setFocusableElement(element) {
|
|
50891
|
+
this.focusableElement = element;
|
|
50892
|
+
}
|
|
50893
|
+
focus() {
|
|
50894
|
+
this.focusableElement?.focus();
|
|
50895
|
+
}
|
|
50896
|
+
}
|
|
50897
|
+
|
|
50767
50898
|
const RIPPLE_KEY_FRAMES = [
|
|
50768
50899
|
{ transform: "scale(0)" },
|
|
50769
50900
|
{ transform: "scale(0.8)", offset: 0.33 },
|
|
@@ -52920,6 +53051,7 @@
|
|
|
52920
53051
|
toggleSidePanel: this.toggleSidePanel.bind(this),
|
|
52921
53052
|
clipboard: this.env.clipboard || instantiateClipboard(),
|
|
52922
53053
|
startCellEdition: (content) => this.onGridComposerCellFocused(content),
|
|
53054
|
+
focusableElement: new FocusableElement(),
|
|
52923
53055
|
});
|
|
52924
53056
|
owl.useExternalListener(window, "resize", () => this.render(true));
|
|
52925
53057
|
owl.useExternalListener(window, "beforeunload", this.unbindModelEvents.bind(this));
|
|
@@ -53026,16 +53158,17 @@
|
|
|
53026
53158
|
}
|
|
53027
53159
|
this.composer.topBarFocus = "contentFocus";
|
|
53028
53160
|
this.composer.gridFocusMode = "inactive";
|
|
53029
|
-
this.setComposerContent({ selection }
|
|
53161
|
+
this.setComposerContent({ selection });
|
|
53030
53162
|
}
|
|
53031
|
-
onGridComposerContentFocused() {
|
|
53163
|
+
onGridComposerContentFocused(selection) {
|
|
53032
53164
|
if (this.model.getters.isReadonly()) {
|
|
53033
53165
|
return;
|
|
53034
53166
|
}
|
|
53035
53167
|
this.composer.topBarFocus = "inactive";
|
|
53036
53168
|
this.composer.gridFocusMode = "contentFocus";
|
|
53037
|
-
this.setComposerContent({});
|
|
53169
|
+
this.setComposerContent({ selection });
|
|
53038
53170
|
}
|
|
53171
|
+
// TODO: either both are defined or none of them. change those args to an object
|
|
53039
53172
|
onGridComposerCellFocused(content, selection) {
|
|
53040
53173
|
if (this.model.getters.isReadonly()) {
|
|
53041
53174
|
return;
|
|
@@ -54461,11 +54594,10 @@
|
|
|
54461
54594
|
* next cluster if the given cell is outside a cluster or at the border of a cluster in the given direction.
|
|
54462
54595
|
*/
|
|
54463
54596
|
getEndOfCluster(startPosition, dim, dir) {
|
|
54464
|
-
const sheet = this.getters.getActiveSheet();
|
|
54465
54597
|
let currentPosition = startPosition;
|
|
54466
54598
|
// If both the current cell and the next cell are not empty, we want to go to the end of the cluster
|
|
54467
54599
|
const nextCellPosition = this.getNextCellPosition(startPosition, dim, dir);
|
|
54468
|
-
let mode = !this.
|
|
54600
|
+
let mode = !this.isEvaluatedCellEmpty(currentPosition) && !this.isEvaluatedCellEmpty(nextCellPosition)
|
|
54469
54601
|
? "endOfCluster"
|
|
54470
54602
|
: "nextCluster";
|
|
54471
54603
|
while (true) {
|
|
@@ -54475,7 +54607,7 @@
|
|
|
54475
54607
|
currentPosition.row === nextCellPosition.row) {
|
|
54476
54608
|
break;
|
|
54477
54609
|
}
|
|
54478
|
-
const isNextCellEmpty = this.
|
|
54610
|
+
const isNextCellEmpty = this.isEvaluatedCellEmpty(nextCellPosition);
|
|
54479
54611
|
if (mode === "endOfCluster" && isNextCellEmpty) {
|
|
54480
54612
|
break;
|
|
54481
54613
|
}
|
|
@@ -54489,10 +54621,20 @@
|
|
|
54489
54621
|
return dim === "cols" ? currentPosition.col : currentPosition.row;
|
|
54490
54622
|
}
|
|
54491
54623
|
/**
|
|
54492
|
-
*
|
|
54493
|
-
* check
|
|
54624
|
+
* Checks if a cell is empty (i.e. does not have a content). If the cell is part of a merge,
|
|
54625
|
+
* the check applies to the main cell of the merge.
|
|
54494
54626
|
*/
|
|
54495
|
-
isCellEmpty({ col, row }
|
|
54627
|
+
isCellEmpty({ col, row }) {
|
|
54628
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
54629
|
+
const position = this.getters.getMainCellPosition({ sheetId, col, row });
|
|
54630
|
+
return !(this.getters.getCorrespondingFormulaCell(position) || this.getters.getCell(position)?.content);
|
|
54631
|
+
}
|
|
54632
|
+
/**
|
|
54633
|
+
* Checks if a cell evaluated value is empty. If the cell is part of a merge,
|
|
54634
|
+
* the check applies to the main cell of the merge.
|
|
54635
|
+
*/
|
|
54636
|
+
isEvaluatedCellEmpty({ col, row }) {
|
|
54637
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
54496
54638
|
const position = this.getters.getMainCellPosition({ sheetId, col, row });
|
|
54497
54639
|
const cell = this.getters.getEvaluatedCell(position);
|
|
54498
54640
|
return cell.type === CellValueType.empty;
|
|
@@ -56798,9 +56940,9 @@
|
|
|
56798
56940
|
exports.tokenize = tokenize;
|
|
56799
56941
|
|
|
56800
56942
|
|
|
56801
|
-
__info__.version = "17.0.
|
|
56802
|
-
__info__.date = "2024-02-
|
|
56803
|
-
__info__.hash = "
|
|
56943
|
+
__info__.version = "17.0.13";
|
|
56944
|
+
__info__.date = "2024-02-28T12:28:44.914Z";
|
|
56945
|
+
__info__.hash = "ed67be7";
|
|
56804
56946
|
|
|
56805
56947
|
|
|
56806
56948
|
})(this.o_spreadsheet = this.o_spreadsheet || {}, owl);
|