@odoo/o-spreadsheet 17.0.10 → 17.0.12
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 +304 -187
- package/dist/o-spreadsheet.d.ts +31 -15
- package/dist/o-spreadsheet.esm.js +304 -187
- package/dist/o-spreadsheet.iife.js +304 -187
- 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.12
|
|
6
|
+
* @date 2024-02-16T14:24:02.984Z
|
|
7
|
+
* @hash 8fa2bab
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
'use strict';
|
|
@@ -552,8 +552,8 @@ function isObjectEmptyRecursive(argument) {
|
|
|
552
552
|
* If the given item does not exist in the dictionary, it creates one with a new id.
|
|
553
553
|
*/
|
|
554
554
|
function getItemId(item, itemsDic) {
|
|
555
|
-
for (
|
|
556
|
-
if (deepEquals(
|
|
555
|
+
for (const key in itemsDic) {
|
|
556
|
+
if (deepEquals(itemsDic[key], item)) {
|
|
557
557
|
return parseInt(key, 10);
|
|
558
558
|
}
|
|
559
559
|
}
|
|
@@ -652,11 +652,13 @@ function deepEquals(o1, o2) {
|
|
|
652
652
|
if (typeof o1 !== "object")
|
|
653
653
|
return o1 === o2;
|
|
654
654
|
// Objects can have different keys if the values are undefined
|
|
655
|
-
const
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
655
|
+
for (const key in o2) {
|
|
656
|
+
if (!(key in o1) && o2[key] !== undefined) {
|
|
657
|
+
return false;
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
for (const key in o1) {
|
|
661
|
+
if (typeof o1[key] !== typeof o2[key])
|
|
660
662
|
return false;
|
|
661
663
|
if (typeof o1[key] === "object") {
|
|
662
664
|
if (!deepEquals(o1[key], o2[key]))
|
|
@@ -726,18 +728,18 @@ function isConsecutive(iterable) {
|
|
|
726
728
|
return true;
|
|
727
729
|
}
|
|
728
730
|
class JetSet extends Set {
|
|
729
|
-
|
|
731
|
+
addMany(iterable) {
|
|
730
732
|
for (const element of iterable) {
|
|
731
733
|
super.add(element);
|
|
732
734
|
}
|
|
733
735
|
return this;
|
|
734
736
|
}
|
|
735
|
-
|
|
736
|
-
let
|
|
737
|
+
deleteMany(iterable) {
|
|
738
|
+
let wasDeleted = false;
|
|
737
739
|
for (const element of iterable) {
|
|
738
|
-
|
|
740
|
+
wasDeleted ||= super.delete(element);
|
|
739
741
|
}
|
|
740
|
-
return
|
|
742
|
+
return wasDeleted;
|
|
741
743
|
}
|
|
742
744
|
}
|
|
743
745
|
/**
|
|
@@ -1996,7 +1998,7 @@ class DispatchResult {
|
|
|
1996
1998
|
* Static helper which returns a successful DispatchResult
|
|
1997
1999
|
*/
|
|
1998
2000
|
static get Success() {
|
|
1999
|
-
return
|
|
2001
|
+
return SUCCESS;
|
|
2000
2002
|
}
|
|
2001
2003
|
get isSuccessful() {
|
|
2002
2004
|
return this.reasons.length === 0;
|
|
@@ -2009,6 +2011,7 @@ class DispatchResult {
|
|
|
2009
2011
|
return this.reasons.includes(reason);
|
|
2010
2012
|
}
|
|
2011
2013
|
}
|
|
2014
|
+
const SUCCESS = new DispatchResult();
|
|
2012
2015
|
exports.CommandResult = void 0;
|
|
2013
2016
|
(function (CommandResult) {
|
|
2014
2017
|
CommandResult["Success"] = "Success";
|
|
@@ -2890,6 +2893,9 @@ function parseFormat(formatString) {
|
|
|
2890
2893
|
function formatValue(value, { format, locale }) {
|
|
2891
2894
|
switch (typeof value) {
|
|
2892
2895
|
case "string":
|
|
2896
|
+
if (value.includes('\\"')) {
|
|
2897
|
+
return value.replace(/\\"/g, '"');
|
|
2898
|
+
}
|
|
2893
2899
|
return value;
|
|
2894
2900
|
case "boolean":
|
|
2895
2901
|
return value ? "TRUE" : "FALSE";
|
|
@@ -7381,7 +7387,7 @@ function tokenize(str, locale = DEFAULT_LOCALE) {
|
|
|
7381
7387
|
while (!chars.isOver()) {
|
|
7382
7388
|
let token = tokenizeSpace(chars) ||
|
|
7383
7389
|
tokenizeArgsSeparator(chars, locale) ||
|
|
7384
|
-
|
|
7390
|
+
tokenizeParenthesis(chars) ||
|
|
7385
7391
|
tokenizeOperator(chars) ||
|
|
7386
7392
|
tokenizeString(chars) ||
|
|
7387
7393
|
tokenizeDebugger(chars) ||
|
|
@@ -7402,15 +7408,14 @@ function tokenizeDebugger(chars) {
|
|
|
7402
7408
|
}
|
|
7403
7409
|
return null;
|
|
7404
7410
|
}
|
|
7405
|
-
const
|
|
7406
|
-
"(": "LEFT_PAREN",
|
|
7407
|
-
")": "RIGHT_PAREN",
|
|
7411
|
+
const parenthesis = {
|
|
7412
|
+
"(": { type: "LEFT_PAREN", value: "(" },
|
|
7413
|
+
")": { type: "RIGHT_PAREN", value: ")" },
|
|
7408
7414
|
};
|
|
7409
|
-
function
|
|
7410
|
-
if (chars.current
|
|
7415
|
+
function tokenizeParenthesis(chars) {
|
|
7416
|
+
if (chars.current === "(" || chars.current === ")") {
|
|
7411
7417
|
const value = chars.shift();
|
|
7412
|
-
|
|
7413
|
-
return { type, value };
|
|
7418
|
+
return parenthesis[value];
|
|
7414
7419
|
}
|
|
7415
7420
|
return null;
|
|
7416
7421
|
}
|
|
@@ -7431,7 +7436,12 @@ function tokenizeOperator(chars) {
|
|
|
7431
7436
|
}
|
|
7432
7437
|
return null;
|
|
7433
7438
|
}
|
|
7439
|
+
const FIRST_POSSIBLE_NUMBER_CHARS = new Set("0123456789");
|
|
7434
7440
|
function tokenizeNumber(chars, locale) {
|
|
7441
|
+
if (!FIRST_POSSIBLE_NUMBER_CHARS.has(chars.current) &&
|
|
7442
|
+
chars.current !== locale.decimalSeparator) {
|
|
7443
|
+
return null;
|
|
7444
|
+
}
|
|
7435
7445
|
const match = chars.remaining().match(getFormulaNumberRegex(locale.decimalSeparator));
|
|
7436
7446
|
if (match) {
|
|
7437
7447
|
chars.advanceBy(match[0].length);
|
|
@@ -7456,7 +7466,7 @@ function tokenizeString(chars) {
|
|
|
7456
7466
|
}
|
|
7457
7467
|
return null;
|
|
7458
7468
|
}
|
|
7459
|
-
const separatorRegexp =
|
|
7469
|
+
const separatorRegexp = /^[\w\.!\$]+/;
|
|
7460
7470
|
/**
|
|
7461
7471
|
* A "Symbol" is just basically any word-like element that can appear in a
|
|
7462
7472
|
* formula, which is not a string. So:
|
|
@@ -7496,8 +7506,11 @@ function tokenizeSymbol(chars) {
|
|
|
7496
7506
|
};
|
|
7497
7507
|
}
|
|
7498
7508
|
}
|
|
7499
|
-
|
|
7500
|
-
|
|
7509
|
+
const match = chars.remaining().match(separatorRegexp);
|
|
7510
|
+
if (match) {
|
|
7511
|
+
const value = match[0];
|
|
7512
|
+
result += value;
|
|
7513
|
+
chars.advanceBy(value.length);
|
|
7501
7514
|
}
|
|
7502
7515
|
if (result.length) {
|
|
7503
7516
|
const value = result;
|
|
@@ -7559,7 +7572,10 @@ class TokenizingChars {
|
|
|
7559
7572
|
return this.text.substring(this.currentIndex);
|
|
7560
7573
|
}
|
|
7561
7574
|
currentStartsWith(str) {
|
|
7562
|
-
|
|
7575
|
+
if (this.current !== str[0]) {
|
|
7576
|
+
return false;
|
|
7577
|
+
}
|
|
7578
|
+
for (let j = 1; j < str.length; j++) {
|
|
7563
7579
|
if (this.text[this.currentIndex + j] !== str[j]) {
|
|
7564
7580
|
return false;
|
|
7565
7581
|
}
|
|
@@ -7586,6 +7602,9 @@ function isValidLocale(locale) {
|
|
|
7586
7602
|
if (locale.formulaArgSeparator === locale.decimalSeparator) {
|
|
7587
7603
|
return false;
|
|
7588
7604
|
}
|
|
7605
|
+
if (locale.thousandsSeparator === locale.decimalSeparator) {
|
|
7606
|
+
return false;
|
|
7607
|
+
}
|
|
7589
7608
|
try {
|
|
7590
7609
|
formatValue(1, { locale, format: "#,##0.00" });
|
|
7591
7610
|
formatValue(1, { locale, format: locale.dateFormat });
|
|
@@ -7676,7 +7695,7 @@ function canonicalizeNumberLiteral(content, locale) {
|
|
|
7676
7695
|
if (locale.decimalSeparator === "." || !isNumber(content, locale)) {
|
|
7677
7696
|
return content;
|
|
7678
7697
|
}
|
|
7679
|
-
return content.replace(locale.decimalSeparator, ".");
|
|
7698
|
+
return content.replace(locale.thousandsSeparator, "").replace(locale.decimalSeparator, ".");
|
|
7680
7699
|
}
|
|
7681
7700
|
/**
|
|
7682
7701
|
* Change a content string from the given locale to its canonical form (en_US locale). Also convert date string.
|
|
@@ -10748,6 +10767,12 @@ const INSERT_LINK = (env) => {
|
|
|
10748
10767
|
let { col, row } = env.model.getters.getActivePosition();
|
|
10749
10768
|
env.model.dispatch("OPEN_CELL_POPOVER", { col, row, popoverType: "LinkEditor" });
|
|
10750
10769
|
};
|
|
10770
|
+
const INSERT_LINK_NAME = (env) => {
|
|
10771
|
+
const sheetId = env.model.getters.getActiveSheetId();
|
|
10772
|
+
const { col, row } = env.model.getters.getActivePosition();
|
|
10773
|
+
const cell = env.model.getters.getEvaluatedCell({ sheetId, col, row });
|
|
10774
|
+
return cell && cell.link ? _t("Edit link") : _t("Insert link");
|
|
10775
|
+
};
|
|
10751
10776
|
//------------------------------------------------------------------------------
|
|
10752
10777
|
// Filters action
|
|
10753
10778
|
//------------------------------------------------------------------------------
|
|
@@ -19779,7 +19804,7 @@ cellMenuRegistry
|
|
|
19779
19804
|
})
|
|
19780
19805
|
.add("insert_link", {
|
|
19781
19806
|
...insertLink,
|
|
19782
|
-
name:
|
|
19807
|
+
name: INSERT_LINK_NAME,
|
|
19783
19808
|
sequence: 150,
|
|
19784
19809
|
separator: true,
|
|
19785
19810
|
});
|
|
@@ -26032,6 +26057,17 @@ css /* scss */ `
|
|
|
26032
26057
|
`;
|
|
26033
26058
|
class TextValueProvider extends owl.Component {
|
|
26034
26059
|
static template = "o-spreadsheet-TextValueProvider";
|
|
26060
|
+
autoCompleteListRef = owl.useRef("autoCompleteList");
|
|
26061
|
+
setup() {
|
|
26062
|
+
owl.useEffect(() => {
|
|
26063
|
+
const selectedIndex = this.props.selectedIndex;
|
|
26064
|
+
if (selectedIndex === undefined) {
|
|
26065
|
+
return;
|
|
26066
|
+
}
|
|
26067
|
+
const selectedElement = this.autoCompleteListRef.el?.children[selectedIndex];
|
|
26068
|
+
selectedElement?.scrollIntoView?.({ block: "nearest" });
|
|
26069
|
+
}, () => [this.props.selectedIndex, this.autoCompleteListRef.el]);
|
|
26070
|
+
}
|
|
26035
26071
|
}
|
|
26036
26072
|
TextValueProvider.props = {
|
|
26037
26073
|
values: Array,
|
|
@@ -26483,6 +26519,7 @@ css /* scss */ `
|
|
|
26483
26519
|
position: absolute;
|
|
26484
26520
|
margin: 1px 4px;
|
|
26485
26521
|
pointer-events: none;
|
|
26522
|
+
overflow: auto;
|
|
26486
26523
|
|
|
26487
26524
|
.o-semi-bold {
|
|
26488
26525
|
/** FIXME: to remove in favor of Bootstrap
|
|
@@ -26498,6 +26535,7 @@ class Composer extends owl.Component {
|
|
|
26498
26535
|
static components = { TextValueProvider, FunctionDescriptionProvider };
|
|
26499
26536
|
static defaultProps = {
|
|
26500
26537
|
inputStyle: "",
|
|
26538
|
+
isDefaultFocus: false,
|
|
26501
26539
|
};
|
|
26502
26540
|
composerRef = owl.useRef("o_composer");
|
|
26503
26541
|
contentHelper = new ContentEditableHelper(this.composerRef.el);
|
|
@@ -26528,7 +26566,10 @@ class Composer extends owl.Component {
|
|
|
26528
26566
|
if (this.props.delimitation && this.props.rect) {
|
|
26529
26567
|
const { x: cellX, y: cellY, height: cellHeight } = this.props.rect;
|
|
26530
26568
|
const remainingHeight = this.props.delimitation.height - (cellY + cellHeight);
|
|
26569
|
+
assistantStyle["max-height"] = `${remainingHeight}px`;
|
|
26531
26570
|
if (cellY > remainingHeight) {
|
|
26571
|
+
const availableSpaceAbove = cellY;
|
|
26572
|
+
assistantStyle["max-height"] = `${availableSpaceAbove}px`;
|
|
26532
26573
|
// render top
|
|
26533
26574
|
// We compensate 2 px of margin on the assistant style + 1px for design reasons
|
|
26534
26575
|
assistantStyle.top = `-3px`;
|
|
@@ -26554,7 +26595,6 @@ class Composer extends owl.Component {
|
|
|
26554
26595
|
F2: () => console.warn("Not implemented"),
|
|
26555
26596
|
F4: this.processF4Key,
|
|
26556
26597
|
Tab: (ev) => this.processTabKey(ev),
|
|
26557
|
-
" ": (ev) => this.processSpaceKey(ev),
|
|
26558
26598
|
};
|
|
26559
26599
|
keyCodeMapping = {
|
|
26560
26600
|
NumpadDecimal: this.processNumpadDecimal,
|
|
@@ -26562,12 +26602,12 @@ class Composer extends owl.Component {
|
|
|
26562
26602
|
setup() {
|
|
26563
26603
|
owl.onMounted(() => {
|
|
26564
26604
|
const el = this.composerRef.el;
|
|
26605
|
+
if (this.props.isDefaultFocus) {
|
|
26606
|
+
this.env.focusableElement.setFocusableElement(el);
|
|
26607
|
+
}
|
|
26565
26608
|
this.contentHelper.updateEl(el);
|
|
26566
26609
|
this.processTokenAtCursor();
|
|
26567
26610
|
});
|
|
26568
|
-
owl.onWillUnmount(() => {
|
|
26569
|
-
this.props.onComposerUnmounted?.();
|
|
26570
|
-
});
|
|
26571
26611
|
owl.useEffect(() => {
|
|
26572
26612
|
this.processContent();
|
|
26573
26613
|
});
|
|
@@ -26576,7 +26616,8 @@ class Composer extends owl.Component {
|
|
|
26576
26616
|
// Handlers
|
|
26577
26617
|
// ---------------------------------------------------------------------------
|
|
26578
26618
|
processArrowKeys(ev) {
|
|
26579
|
-
if (this.env.model.getters.isSelectingForComposer()
|
|
26619
|
+
if (this.env.model.getters.isSelectingForComposer() ||
|
|
26620
|
+
this.env.model.getters.getEditionMode() === "inactive") {
|
|
26580
26621
|
this.functionDescriptionState.showDescription = false;
|
|
26581
26622
|
// Prevent the default content editable behavior which moves the cursor
|
|
26582
26623
|
ev.preventDefault();
|
|
@@ -26619,26 +26660,20 @@ class Composer extends owl.Component {
|
|
|
26619
26660
|
processTabKey(ev) {
|
|
26620
26661
|
ev.preventDefault();
|
|
26621
26662
|
ev.stopPropagation();
|
|
26622
|
-
|
|
26623
|
-
|
|
26624
|
-
|
|
26625
|
-
|
|
26626
|
-
|
|
26627
|
-
|
|
26663
|
+
if (this.env.model.getters.getEditionMode() !== "inactive") {
|
|
26664
|
+
const state = this.autoCompleteState;
|
|
26665
|
+
if (state.showProvider && state.selectedIndex !== undefined) {
|
|
26666
|
+
const autoCompleteValue = this.autoCompleteState.values[state.selectedIndex]?.text;
|
|
26667
|
+
if (autoCompleteValue) {
|
|
26668
|
+
this.autoComplete(autoCompleteValue);
|
|
26669
|
+
return;
|
|
26670
|
+
}
|
|
26628
26671
|
}
|
|
26672
|
+
interactiveStopEdition(this.env);
|
|
26629
26673
|
}
|
|
26630
26674
|
const direction = ev.shiftKey ? "left" : "right";
|
|
26631
|
-
interactiveStopEdition(this.env);
|
|
26632
26675
|
this.env.model.selection.moveAnchorCell(direction, 1);
|
|
26633
26676
|
}
|
|
26634
|
-
processSpaceKey(ev) {
|
|
26635
|
-
if (ev.ctrlKey) {
|
|
26636
|
-
ev.preventDefault();
|
|
26637
|
-
ev.stopPropagation();
|
|
26638
|
-
this.showFunctionAutocomplete("");
|
|
26639
|
-
this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
|
|
26640
|
-
}
|
|
26641
|
-
}
|
|
26642
26677
|
processEnterKey(ev) {
|
|
26643
26678
|
ev.preventDefault();
|
|
26644
26679
|
ev.stopPropagation();
|
|
@@ -26691,6 +26726,9 @@ class Composer extends owl.Component {
|
|
|
26691
26726
|
this.compositionActive = false;
|
|
26692
26727
|
}
|
|
26693
26728
|
onKeydown(ev) {
|
|
26729
|
+
if (this.env.model.getters.getEditionMode() === "inactive") {
|
|
26730
|
+
return;
|
|
26731
|
+
}
|
|
26694
26732
|
let handler = this.keyMapping[ev.key] || this.keyCodeMapping[ev.code];
|
|
26695
26733
|
if (handler) {
|
|
26696
26734
|
handler.call(this, ev);
|
|
@@ -26699,14 +26737,33 @@ class Composer extends owl.Component {
|
|
|
26699
26737
|
ev.stopPropagation();
|
|
26700
26738
|
}
|
|
26701
26739
|
}
|
|
26740
|
+
onPaste(ev) {
|
|
26741
|
+
if (this.env.model.getters.getEditionMode() !== "inactive") {
|
|
26742
|
+
ev.stopPropagation();
|
|
26743
|
+
}
|
|
26744
|
+
}
|
|
26702
26745
|
/*
|
|
26703
26746
|
* Triggered automatically by the content-editable between the keydown and key up
|
|
26704
26747
|
* */
|
|
26705
26748
|
onInput(ev) {
|
|
26706
|
-
if (
|
|
26749
|
+
if (!this.shouldProcessInputEvents) {
|
|
26707
26750
|
return;
|
|
26708
26751
|
}
|
|
26709
|
-
|
|
26752
|
+
if (ev.inputType === "insertFromPaste" &&
|
|
26753
|
+
this.env.model.getters.getEditionMode() === "inactive") {
|
|
26754
|
+
return;
|
|
26755
|
+
}
|
|
26756
|
+
ev.stopPropagation();
|
|
26757
|
+
let content;
|
|
26758
|
+
if (this.env.model.getters.getEditionMode() === "inactive") {
|
|
26759
|
+
content = ev.data || "";
|
|
26760
|
+
}
|
|
26761
|
+
else {
|
|
26762
|
+
content = this.contentHelper.getText();
|
|
26763
|
+
}
|
|
26764
|
+
if (this.props.focus === "inactive") {
|
|
26765
|
+
return this.props.onComposerCellFocused?.(content);
|
|
26766
|
+
}
|
|
26710
26767
|
let selection = this.contentHelper.getCurrentSelection();
|
|
26711
26768
|
if (ev.inputType === "insertParagraph") {
|
|
26712
26769
|
const start = Math.min(selection.start, selection.end);
|
|
@@ -26788,9 +26845,8 @@ class Composer extends owl.Component {
|
|
|
26788
26845
|
}
|
|
26789
26846
|
const newSelection = this.contentHelper.getCurrentSelection();
|
|
26790
26847
|
this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
|
|
26791
|
-
|
|
26792
|
-
|
|
26793
|
-
}
|
|
26848
|
+
this.props.onComposerContentFocused();
|
|
26849
|
+
if (this.props.focus === "inactive") ;
|
|
26794
26850
|
this.env.model.dispatch("CHANGE_COMPOSER_CURSOR_SELECTION", newSelection);
|
|
26795
26851
|
this.processTokenAtCursor();
|
|
26796
26852
|
}
|
|
@@ -26957,7 +27013,7 @@ class Composer extends owl.Component {
|
|
|
26957
27013
|
const highlights = this.env.model.getters.getHighlights();
|
|
26958
27014
|
const refSheet = sheetName
|
|
26959
27015
|
? this.env.model.getters.getSheetIdByName(sheetName)
|
|
26960
|
-
: this.env.model.getters.getCurrentEditedCell()
|
|
27016
|
+
: this.env.model.getters.getCurrentEditedCell()?.sheetId;
|
|
26961
27017
|
const highlight = highlights.find((highlight) => {
|
|
26962
27018
|
if (highlight.sheetId !== refSheet)
|
|
26963
27019
|
return false;
|
|
@@ -27050,12 +27106,13 @@ class Composer extends owl.Component {
|
|
|
27050
27106
|
}
|
|
27051
27107
|
}
|
|
27052
27108
|
Composer.props = {
|
|
27053
|
-
focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
|
|
27054
|
-
onComposerContentFocused: Function,
|
|
27055
27109
|
inputStyle: { type: String, optional: true },
|
|
27056
27110
|
rect: { type: Object, optional: true },
|
|
27057
27111
|
delimitation: { type: Object, optional: true },
|
|
27058
|
-
|
|
27112
|
+
focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
|
|
27113
|
+
onComposerCellFocused: { type: Function, optional: true },
|
|
27114
|
+
onComposerContentFocused: Function,
|
|
27115
|
+
isDefaultFocus: { type: Boolean, optional: true },
|
|
27059
27116
|
};
|
|
27060
27117
|
|
|
27061
27118
|
const COMPOSER_BORDER_WIDTH = 3 * 0.4 * window.devicePixelRatio || 1;
|
|
@@ -27089,51 +27146,25 @@ css /* scss */ `
|
|
|
27089
27146
|
class GridComposer extends owl.Component {
|
|
27090
27147
|
static template = "o-spreadsheet-GridComposer";
|
|
27091
27148
|
static components = { Composer };
|
|
27092
|
-
|
|
27093
|
-
|
|
27094
|
-
rect;
|
|
27149
|
+
rect = this.defaultRect;
|
|
27150
|
+
isEditing = false;
|
|
27095
27151
|
isCellReferenceVisible;
|
|
27096
|
-
|
|
27152
|
+
get defaultRect() {
|
|
27153
|
+
return { x: 0, y: 0, width: 0, height: 0 };
|
|
27154
|
+
}
|
|
27097
27155
|
setup() {
|
|
27098
|
-
this.gridComposerRef = owl.useRef("gridComposer");
|
|
27099
|
-
this.composerState = owl.useState({
|
|
27100
|
-
rect: undefined,
|
|
27101
|
-
delimitation: undefined,
|
|
27102
|
-
});
|
|
27103
|
-
const { sheetId, col, row } = this.env.model.getters.getActivePosition();
|
|
27104
|
-
this.zone = this.env.model.getters.expandZone(sheetId, positionToZone({ col, row }));
|
|
27105
|
-
this.rect = this.env.model.getters.getVisibleRect(this.zone);
|
|
27106
|
-
this.isCellReferenceVisible = false;
|
|
27107
|
-
owl.onMounted(() => {
|
|
27108
|
-
const el = this.gridComposerRef.el;
|
|
27109
|
-
this.composerState.rect = {
|
|
27110
|
-
x: this.rect.x,
|
|
27111
|
-
y: this.rect.y,
|
|
27112
|
-
width: el.clientWidth,
|
|
27113
|
-
height: el.clientHeight,
|
|
27114
|
-
};
|
|
27115
|
-
this.composerState.delimitation = {
|
|
27116
|
-
width: this.props.gridDims.width,
|
|
27117
|
-
height: this.props.gridDims.height,
|
|
27118
|
-
};
|
|
27119
|
-
});
|
|
27120
27156
|
owl.onWillUpdateProps(() => {
|
|
27121
|
-
|
|
27122
|
-
|
|
27123
|
-
}
|
|
27124
|
-
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
27125
|
-
const zone = this.env.model.getters.getSelectedZone();
|
|
27126
|
-
const rect = this.env.model.getters.getVisibleRect(zone);
|
|
27127
|
-
if (!deepEquals(rect, this.rect) ||
|
|
27128
|
-
sheetId !== this.env.model.getters.getCurrentEditedCell().sheetId) {
|
|
27129
|
-
this.isCellReferenceVisible = true;
|
|
27130
|
-
}
|
|
27157
|
+
this.updateComponentPosition();
|
|
27158
|
+
this.updateCellReferenceVisibility();
|
|
27131
27159
|
});
|
|
27132
27160
|
}
|
|
27133
27161
|
get shouldDisplayCellReference() {
|
|
27134
27162
|
return this.isCellReferenceVisible;
|
|
27135
27163
|
}
|
|
27136
27164
|
get cellReference() {
|
|
27165
|
+
if (!this.env.model.getters.getCurrentEditedCell()) {
|
|
27166
|
+
return "";
|
|
27167
|
+
}
|
|
27137
27168
|
const { col, row, sheetId } = this.env.model.getters.getCurrentEditedCell();
|
|
27138
27169
|
const prefixSheet = sheetId !== this.env.model.getters.getActiveSheetId();
|
|
27139
27170
|
return `${prefixSheet ? getCanonicalSheetName(this.env.model.getters.getSheetName(sheetId)) + "!" : ""}${toXC(col, row)}`;
|
|
@@ -27145,7 +27176,27 @@ class GridComposer extends owl.Component {
|
|
|
27145
27176
|
top: `${top - GRID_CELL_REFERENCE_TOP_OFFSET}px`,
|
|
27146
27177
|
});
|
|
27147
27178
|
}
|
|
27179
|
+
get composerProps() {
|
|
27180
|
+
const { width, height } = this.env.model.getters.getSheetViewDimensionWithHeaders();
|
|
27181
|
+
return {
|
|
27182
|
+
rect: { ...this.rect },
|
|
27183
|
+
delimitation: {
|
|
27184
|
+
width,
|
|
27185
|
+
height,
|
|
27186
|
+
},
|
|
27187
|
+
focus: this.props.focus,
|
|
27188
|
+
isDefaultFocus: true,
|
|
27189
|
+
onComposerContentFocused: this.props.onComposerContentFocused,
|
|
27190
|
+
onComposerCellFocused: this.props.onComposerCellFocused,
|
|
27191
|
+
};
|
|
27192
|
+
}
|
|
27148
27193
|
get containerStyle() {
|
|
27194
|
+
if (this.env.model.getters.getEditionMode() === "inactive" || !this.rect) {
|
|
27195
|
+
return `
|
|
27196
|
+
position: absolute;
|
|
27197
|
+
z-index: -1000;
|
|
27198
|
+
`;
|
|
27199
|
+
}
|
|
27149
27200
|
const isFormula = this.env.model.getters.getCurrentContent().startsWith("=");
|
|
27150
27201
|
const cell = this.env.model.getters.getActiveCell();
|
|
27151
27202
|
const position = this.env.model.getters.getActivePosition();
|
|
@@ -27165,6 +27216,8 @@ class GridComposer extends owl.Component {
|
|
|
27165
27216
|
if (!isFormula) {
|
|
27166
27217
|
textAlign = style.align || cell.defaultAlign;
|
|
27167
27218
|
}
|
|
27219
|
+
const maxHeight = this.props.gridDims.height - this.rect.y;
|
|
27220
|
+
const maxWidth = this.props.gridDims.width - this.rect.x;
|
|
27168
27221
|
/**
|
|
27169
27222
|
* min-size is on the container, not the composer element, because we want to have the same size as the cell by default,
|
|
27170
27223
|
* including all the paddings/margins of the composer
|
|
@@ -27176,6 +27229,8 @@ class GridComposer extends owl.Component {
|
|
|
27176
27229
|
top: `${top}px`,
|
|
27177
27230
|
"min-width": `${width + 1}px`,
|
|
27178
27231
|
"min-height": `${height + 1}px`,
|
|
27232
|
+
"max-width": `${maxWidth}px`,
|
|
27233
|
+
"max-height": `${maxHeight}px`,
|
|
27179
27234
|
background,
|
|
27180
27235
|
color,
|
|
27181
27236
|
"font-size": `${fontSizeInPixels(fontSize)}px`,
|
|
@@ -27185,20 +27240,38 @@ class GridComposer extends owl.Component {
|
|
|
27185
27240
|
"text-align": textAlign,
|
|
27186
27241
|
});
|
|
27187
27242
|
}
|
|
27188
|
-
|
|
27189
|
-
const
|
|
27190
|
-
|
|
27191
|
-
|
|
27192
|
-
|
|
27193
|
-
|
|
27194
|
-
|
|
27243
|
+
updateComponentPosition() {
|
|
27244
|
+
const isEditing = this.env.model.getters.getEditionMode() !== "inactive";
|
|
27245
|
+
if (this.isEditing !== isEditing) {
|
|
27246
|
+
this.isEditing = isEditing;
|
|
27247
|
+
if (!isEditing) {
|
|
27248
|
+
this.rect = this.defaultRect;
|
|
27249
|
+
this.env.focusableElement.focus();
|
|
27250
|
+
return;
|
|
27251
|
+
}
|
|
27252
|
+
const position = this.env.model.getters.getActivePosition();
|
|
27253
|
+
const zone = this.env.model.getters.expandZone(position.sheetId, positionToZone(position));
|
|
27254
|
+
this.rect = this.env.model.getters.getVisibleRect(zone);
|
|
27255
|
+
}
|
|
27256
|
+
}
|
|
27257
|
+
updateCellReferenceVisibility() {
|
|
27258
|
+
if (this.isCellReferenceVisible || this.env.model.getters.getEditionMode() === "inactive") {
|
|
27259
|
+
return;
|
|
27260
|
+
}
|
|
27261
|
+
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
27262
|
+
const zone = this.env.model.getters.getSelectedZone();
|
|
27263
|
+
const rect = this.env.model.getters.getVisibleRect(zone);
|
|
27264
|
+
if (!deepEquals(rect, this.rect) ||
|
|
27265
|
+
sheetId !== this.env.model.getters.getCurrentEditedCell().sheetId) {
|
|
27266
|
+
this.isCellReferenceVisible = true;
|
|
27267
|
+
}
|
|
27195
27268
|
}
|
|
27196
27269
|
}
|
|
27197
27270
|
GridComposer.props = {
|
|
27198
27271
|
focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
|
|
27199
|
-
onComposerUnmounted: Function,
|
|
27200
27272
|
onComposerContentFocused: Function,
|
|
27201
27273
|
gridDims: Object,
|
|
27274
|
+
onComposerCellFocused: Function,
|
|
27202
27275
|
};
|
|
27203
27276
|
|
|
27204
27277
|
const CSS$1 = css /* scss */ `
|
|
@@ -28289,7 +28362,6 @@ class GridOverlay extends owl.Component {
|
|
|
28289
28362
|
this.props.onCellDoubleClicked(col, row);
|
|
28290
28363
|
}
|
|
28291
28364
|
onContextMenu(ev) {
|
|
28292
|
-
ev.preventDefault();
|
|
28293
28365
|
const [col, row] = this.getCartesianCoordinates(ev);
|
|
28294
28366
|
this.props.onCellRightClicked(col, row, { x: ev.clientX, y: ev.clientY });
|
|
28295
28367
|
}
|
|
@@ -29374,7 +29446,6 @@ class Grid extends owl.Component {
|
|
|
29374
29446
|
HEADER_WIDTH = HEADER_WIDTH;
|
|
29375
29447
|
menuState;
|
|
29376
29448
|
gridRef;
|
|
29377
|
-
hiddenInput;
|
|
29378
29449
|
onMouseWheel;
|
|
29379
29450
|
canvasPosition;
|
|
29380
29451
|
hoveredCell;
|
|
@@ -29385,17 +29456,16 @@ class Grid extends owl.Component {
|
|
|
29385
29456
|
menuItems: [],
|
|
29386
29457
|
});
|
|
29387
29458
|
this.gridRef = owl.useRef("grid");
|
|
29388
|
-
this.hiddenInput = owl.useRef("hiddenInput");
|
|
29389
29459
|
this.canvasPosition = useAbsoluteBoundingRect(this.gridRef);
|
|
29390
29460
|
this.hoveredCell = owl.useState({ col: undefined, row: undefined });
|
|
29391
29461
|
owl.useChildSubEnv({ getPopoverContainerRect: () => this.getGridRect() });
|
|
29392
29462
|
owl.useExternalListener(document.body, "cut", this.copy.bind(this, true));
|
|
29393
29463
|
owl.useExternalListener(document.body, "copy", this.copy.bind(this, false));
|
|
29394
29464
|
owl.useExternalListener(document.body, "paste", this.paste);
|
|
29395
|
-
owl.onMounted(() => this.
|
|
29396
|
-
this.props.exposeFocus(() => this.
|
|
29465
|
+
owl.onMounted(() => this.focusDefaultElement());
|
|
29466
|
+
this.props.exposeFocus(() => this.focusDefaultElement());
|
|
29397
29467
|
useGridDrawing("canvas", this.env.model, () => this.env.model.getters.getSheetViewDimensionWithHeaders());
|
|
29398
|
-
owl.useEffect(() => this.
|
|
29468
|
+
owl.useEffect(() => this.focusDefaultElement(), () => [this.env.model.getters.getActiveSheetId()]);
|
|
29399
29469
|
this.onMouseWheel = useWheelHandler((deltaX, deltaY) => {
|
|
29400
29470
|
this.moveCanvas(deltaX, deltaY);
|
|
29401
29471
|
this.hoveredCell.col = undefined;
|
|
@@ -29418,7 +29488,7 @@ class Grid extends owl.Component {
|
|
|
29418
29488
|
if (this.env.model.getters.hasOpenedPopover()) {
|
|
29419
29489
|
this.closeOpenedPopover();
|
|
29420
29490
|
}
|
|
29421
|
-
this.
|
|
29491
|
+
this.focusDefaultElement();
|
|
29422
29492
|
}
|
|
29423
29493
|
// this map will handle most of the actions that should happen on key down. The arrow keys are managed in the key
|
|
29424
29494
|
// down itself
|
|
@@ -29597,10 +29667,10 @@ class Grid extends owl.Component {
|
|
|
29597
29667
|
"ALT+SHIFT+ARROWUP": () => this.processHeaderGroupingKey("up"),
|
|
29598
29668
|
"ALT+SHIFT+ARROWDOWN": () => this.processHeaderGroupingKey("down"),
|
|
29599
29669
|
};
|
|
29600
|
-
|
|
29670
|
+
focusDefaultElement() {
|
|
29601
29671
|
if (!this.env.model.getters.getSelectedFigureId() &&
|
|
29602
29672
|
this.env.model.getters.getEditionMode() === "inactive") {
|
|
29603
|
-
this.
|
|
29673
|
+
this.env.focusableElement.focus();
|
|
29604
29674
|
}
|
|
29605
29675
|
}
|
|
29606
29676
|
get gridEl() {
|
|
@@ -29745,19 +29815,6 @@ class Grid extends owl.Component {
|
|
|
29745
29815
|
return;
|
|
29746
29816
|
}
|
|
29747
29817
|
}
|
|
29748
|
-
onInput(ev) {
|
|
29749
|
-
// the user meant to paste in the sheet, not open the composer with the pasted content
|
|
29750
|
-
if (!ev.isComposing && ev.inputType === "insertFromPaste") {
|
|
29751
|
-
return;
|
|
29752
|
-
}
|
|
29753
|
-
if (ev.data) {
|
|
29754
|
-
// if the user types a character on the grid, it means he wants to start composing the selected cell with that
|
|
29755
|
-
// character
|
|
29756
|
-
ev.preventDefault();
|
|
29757
|
-
ev.stopPropagation();
|
|
29758
|
-
this.props.onGridComposerCellFocused(ev.data);
|
|
29759
|
-
}
|
|
29760
|
-
}
|
|
29761
29818
|
// ---------------------------------------------------------------------------
|
|
29762
29819
|
// Context Menu
|
|
29763
29820
|
// ---------------------------------------------------------------------------
|
|
@@ -29872,7 +29929,7 @@ class Grid extends owl.Component {
|
|
|
29872
29929
|
}
|
|
29873
29930
|
closeMenu() {
|
|
29874
29931
|
this.menuState.isOpen = false;
|
|
29875
|
-
this.
|
|
29932
|
+
this.focusDefaultElement();
|
|
29876
29933
|
}
|
|
29877
29934
|
processHeaderGroupingKey(direction) {
|
|
29878
29935
|
if (this.env.model.getters.getSelectedZones().length !== 1) {
|
|
@@ -33767,6 +33824,31 @@ const MIGRATIONS = [
|
|
|
33767
33824
|
return data;
|
|
33768
33825
|
},
|
|
33769
33826
|
},
|
|
33827
|
+
{
|
|
33828
|
+
description: "Fix datafilter duplication",
|
|
33829
|
+
from: 12,
|
|
33830
|
+
to: 12.5,
|
|
33831
|
+
applyMigration(data) {
|
|
33832
|
+
for (let sheet of data.sheets || []) {
|
|
33833
|
+
let knownDataFilterZones = [];
|
|
33834
|
+
for (let filterTable of sheet.filterTables || []) {
|
|
33835
|
+
const zone = toZone(filterTable.range);
|
|
33836
|
+
// See commit message for the details
|
|
33837
|
+
const intersectZoneIndex = knownDataFilterZones.findIndex((knownZone) => overlap(knownZone, zone));
|
|
33838
|
+
if (intersectZoneIndex !== -1) {
|
|
33839
|
+
knownDataFilterZones[intersectZoneIndex] = zone;
|
|
33840
|
+
}
|
|
33841
|
+
else {
|
|
33842
|
+
knownDataFilterZones.push(zone);
|
|
33843
|
+
}
|
|
33844
|
+
}
|
|
33845
|
+
sheet.filterTables = knownDataFilterZones.map((zone) => ({
|
|
33846
|
+
range: zoneToXc(zone),
|
|
33847
|
+
}));
|
|
33848
|
+
}
|
|
33849
|
+
return data;
|
|
33850
|
+
},
|
|
33851
|
+
},
|
|
33770
33852
|
{
|
|
33771
33853
|
description: "Change Border description structure",
|
|
33772
33854
|
from: 12,
|
|
@@ -34606,22 +34688,7 @@ class BordersPlugin extends CorePlugin {
|
|
|
34606
34688
|
}
|
|
34607
34689
|
}
|
|
34608
34690
|
export(data) {
|
|
34609
|
-
// Borders
|
|
34610
|
-
let borderId = 0;
|
|
34611
34691
|
const borders = {};
|
|
34612
|
-
/**
|
|
34613
|
-
* Get the id of the given border. If the border does not exist, it creates
|
|
34614
|
-
* one.
|
|
34615
|
-
*/
|
|
34616
|
-
function getBorderId(border) {
|
|
34617
|
-
for (let [key, value] of Object.entries(borders)) {
|
|
34618
|
-
if (deepEquals(value, border)) {
|
|
34619
|
-
return parseInt(key, 10);
|
|
34620
|
-
}
|
|
34621
|
-
}
|
|
34622
|
-
borders[++borderId] = border;
|
|
34623
|
-
return borderId;
|
|
34624
|
-
}
|
|
34625
34692
|
for (let sheet of data.sheets) {
|
|
34626
34693
|
for (let col = 0; col < sheet.colNumber; col++) {
|
|
34627
34694
|
for (let row = 0; row < sheet.rowNumber; row++) {
|
|
@@ -34629,7 +34696,7 @@ class BordersPlugin extends CorePlugin {
|
|
|
34629
34696
|
if (border) {
|
|
34630
34697
|
const xc = toXC(col, row);
|
|
34631
34698
|
const cell = sheet.cells[xc];
|
|
34632
|
-
const borderId =
|
|
34699
|
+
const borderId = getItemId(border, borders);
|
|
34633
34700
|
if (cell) {
|
|
34634
34701
|
cell.border = borderId;
|
|
34635
34702
|
}
|
|
@@ -35434,9 +35501,9 @@ class CellPlugin extends CorePlugin {
|
|
|
35434
35501
|
allowDispatch(cmd) {
|
|
35435
35502
|
switch (cmd.type) {
|
|
35436
35503
|
case "UPDATE_CELL":
|
|
35437
|
-
return this.
|
|
35504
|
+
return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessUpdateCell);
|
|
35438
35505
|
case "CLEAR_CELL":
|
|
35439
|
-
return this.checkValidations(cmd, this.
|
|
35506
|
+
return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessClearCell);
|
|
35440
35507
|
default:
|
|
35441
35508
|
return "Success" /* CommandResult.Success */;
|
|
35442
35509
|
}
|
|
@@ -35569,9 +35636,6 @@ class CellPlugin extends CorePlugin {
|
|
|
35569
35636
|
format: cell.format ? getItemId(cell.format, formats) : undefined,
|
|
35570
35637
|
content: cell.content || undefined,
|
|
35571
35638
|
};
|
|
35572
|
-
if (cell instanceof FormulaCellWithDependencies) {
|
|
35573
|
-
cells[xc].content = cell.contentWithFixedReferences || undefined;
|
|
35574
|
-
}
|
|
35575
35639
|
}
|
|
35576
35640
|
_sheet.cells = cells;
|
|
35577
35641
|
}
|
|
@@ -35589,8 +35653,8 @@ class CellPlugin extends CorePlugin {
|
|
|
35589
35653
|
}
|
|
35590
35654
|
removeDefaultStyleValues(style) {
|
|
35591
35655
|
const cleanedStyle = { ...style };
|
|
35592
|
-
for (const
|
|
35593
|
-
if (cleanedStyle[property] ===
|
|
35656
|
+
for (const property in DEFAULT_STYLE) {
|
|
35657
|
+
if (cleanedStyle[property] === DEFAULT_STYLE[property]) {
|
|
35594
35658
|
delete cleanedStyle[property];
|
|
35595
35659
|
}
|
|
35596
35660
|
}
|
|
@@ -35747,10 +35811,7 @@ class CellPlugin extends CorePlugin {
|
|
|
35747
35811
|
else {
|
|
35748
35812
|
style = before ? before.style : undefined;
|
|
35749
35813
|
}
|
|
35750
|
-
const
|
|
35751
|
-
let format = ("format" in after ? after.format : before && before.format) ||
|
|
35752
|
-
detectDateFormat(afterContent, locale) ||
|
|
35753
|
-
detectNumberFormat(afterContent);
|
|
35814
|
+
const format = "format" in after ? after.format : before && before.format;
|
|
35754
35815
|
/* Read the following IF as:
|
|
35755
35816
|
* we need to remove the cell if it is completely empty, but we can know if it completely empty if:
|
|
35756
35817
|
* - the command says the new content is empty and has no border/format/style
|
|
@@ -35791,12 +35852,11 @@ class CellPlugin extends CorePlugin {
|
|
|
35791
35852
|
}
|
|
35792
35853
|
createLiteralCell(id, content, format, style) {
|
|
35793
35854
|
const locale = this.getters.getLocale();
|
|
35794
|
-
content = parseLiteral(content, locale).toString();
|
|
35795
35855
|
return {
|
|
35796
35856
|
id,
|
|
35797
|
-
content,
|
|
35857
|
+
content: parseLiteral(content, locale).toString(),
|
|
35798
35858
|
style,
|
|
35799
|
-
format,
|
|
35859
|
+
format: format || detectDateFormat(content, locale) || detectNumberFormat(content),
|
|
35800
35860
|
isFormula: false,
|
|
35801
35861
|
};
|
|
35802
35862
|
}
|
|
@@ -35822,8 +35882,11 @@ class CellPlugin extends CorePlugin {
|
|
|
35822
35882
|
* being a computed property to rebuild the dependencies XC.
|
|
35823
35883
|
*/
|
|
35824
35884
|
createFormulaCellWithDependencies(id, compiledFormula, format, style, sheetId) {
|
|
35825
|
-
const dependencies =
|
|
35826
|
-
|
|
35885
|
+
const dependencies = [];
|
|
35886
|
+
for (const xc of compiledFormula.dependencies) {
|
|
35887
|
+
dependencies.push(this.getters.getRangeFromSheetXC(sheetId, xc));
|
|
35888
|
+
}
|
|
35889
|
+
return new FormulaCellWithDependencies(id, compiledFormula, format, style, dependencies, sheetId, this.getters.getRangeString);
|
|
35827
35890
|
}
|
|
35828
35891
|
createErrorFormula(id, content, format, style, error) {
|
|
35829
35892
|
return {
|
|
@@ -35858,6 +35921,18 @@ class CellPlugin extends CorePlugin {
|
|
|
35858
35921
|
}
|
|
35859
35922
|
return "Success" /* CommandResult.Success */;
|
|
35860
35923
|
}
|
|
35924
|
+
checkUselessUpdateCell(cmd) {
|
|
35925
|
+
const cell = this.getters.getCell(cmd);
|
|
35926
|
+
const hasContent = "content" in cmd || "formula" in cmd;
|
|
35927
|
+
const hasStyle = "style" in cmd;
|
|
35928
|
+
const hasFormat = "format" in cmd;
|
|
35929
|
+
if ((!hasContent || cell?.content === cmd.content) &&
|
|
35930
|
+
(!hasStyle || deepEquals(cell?.style, cmd.style)) &&
|
|
35931
|
+
(!hasFormat || cell?.format === cmd.format)) {
|
|
35932
|
+
return "NoChanges" /* CommandResult.NoChanges */;
|
|
35933
|
+
}
|
|
35934
|
+
return "Success" /* CommandResult.Success */;
|
|
35935
|
+
}
|
|
35861
35936
|
}
|
|
35862
35937
|
class FormulaCellWithDependencies {
|
|
35863
35938
|
id;
|
|
@@ -35877,7 +35952,7 @@ class FormulaCellWithDependencies {
|
|
|
35877
35952
|
const tokens = compiledFormula.tokens.map((token) => {
|
|
35878
35953
|
if (token.type === "REFERENCE") {
|
|
35879
35954
|
const index = rangeIndex++;
|
|
35880
|
-
return new RangeReferenceToken(
|
|
35955
|
+
return new RangeReferenceToken(dependencies, index, this.sheetId, this.getRangeString);
|
|
35881
35956
|
}
|
|
35882
35957
|
return token;
|
|
35883
35958
|
});
|
|
@@ -35904,13 +35979,20 @@ class FormulaCellWithDependencies {
|
|
|
35904
35979
|
}
|
|
35905
35980
|
}
|
|
35906
35981
|
class RangeReferenceToken {
|
|
35907
|
-
|
|
35982
|
+
ranges;
|
|
35983
|
+
rangeIndex;
|
|
35984
|
+
sheetId;
|
|
35985
|
+
getRangeString;
|
|
35908
35986
|
type = "REFERENCE";
|
|
35909
|
-
constructor(
|
|
35910
|
-
this.
|
|
35987
|
+
constructor(ranges, rangeIndex, sheetId, getRangeString) {
|
|
35988
|
+
this.ranges = ranges;
|
|
35989
|
+
this.rangeIndex = rangeIndex;
|
|
35990
|
+
this.sheetId = sheetId;
|
|
35991
|
+
this.getRangeString = getRangeString;
|
|
35911
35992
|
}
|
|
35912
35993
|
get value() {
|
|
35913
|
-
|
|
35994
|
+
const range = this.ranges[this.rangeIndex];
|
|
35995
|
+
return this.getRangeString(range, this.sheetId);
|
|
35914
35996
|
}
|
|
35915
35997
|
}
|
|
35916
35998
|
|
|
@@ -40646,7 +40728,15 @@ class SpreadsheetRTree {
|
|
|
40646
40728
|
if (!this.rTrees[sheetId]) {
|
|
40647
40729
|
return;
|
|
40648
40730
|
}
|
|
40649
|
-
this.rTrees[sheetId].remove(item,
|
|
40731
|
+
this.rTrees[sheetId].remove(item, this.rtreeItemComparer);
|
|
40732
|
+
}
|
|
40733
|
+
rtreeItemComparer(left, right) {
|
|
40734
|
+
return (left.data == right.data &&
|
|
40735
|
+
left.boundingBox.sheetId === right.boundingBox.sheetId &&
|
|
40736
|
+
left.boundingBox?.zone.left === right.boundingBox.zone.left &&
|
|
40737
|
+
left.boundingBox?.zone.top === right.boundingBox.zone.top &&
|
|
40738
|
+
left.boundingBox?.zone.right === right.boundingBox.zone.right &&
|
|
40739
|
+
left.boundingBox?.zone.bottom === right.boundingBox.zone.bottom);
|
|
40650
40740
|
}
|
|
40651
40741
|
}
|
|
40652
40742
|
/**
|
|
@@ -40724,7 +40814,7 @@ class FormulaDependencyGraph {
|
|
|
40724
40814
|
const queue = Array.from(ranges).reverse();
|
|
40725
40815
|
while (queue.length > 0) {
|
|
40726
40816
|
const range = queue.pop();
|
|
40727
|
-
visited.
|
|
40817
|
+
visited.addMany(this.encoder.encodeBoundingBox(range));
|
|
40728
40818
|
const impactedPositionIds = this.rTree.search(range).map((dep) => dep.data);
|
|
40729
40819
|
for (const positionId of impactedPositionIds) {
|
|
40730
40820
|
if (!visited.has(positionId)) {
|
|
@@ -40732,7 +40822,7 @@ class FormulaDependencyGraph {
|
|
|
40732
40822
|
}
|
|
40733
40823
|
}
|
|
40734
40824
|
}
|
|
40735
|
-
visited.
|
|
40825
|
+
visited.deleteMany(ranges.flatMap((r) => this.encoder.encodeBoundingBox(r)));
|
|
40736
40826
|
return visited;
|
|
40737
40827
|
}
|
|
40738
40828
|
}
|
|
@@ -40870,9 +40960,9 @@ class Evaluator {
|
|
|
40870
40960
|
const cells = positions.map((p) => this.encoder.encode(p));
|
|
40871
40961
|
const cellsToCompute = new JetSet(cells);
|
|
40872
40962
|
const arrayFormulasPositionIds = this.getArrayFormulasImpactedByChangesOf(cells);
|
|
40873
|
-
cellsToCompute.
|
|
40874
|
-
cellsToCompute.
|
|
40875
|
-
cellsToCompute.
|
|
40963
|
+
cellsToCompute.addMany(this.getCellsDependingOn(cells));
|
|
40964
|
+
cellsToCompute.addMany(arrayFormulasPositionIds);
|
|
40965
|
+
cellsToCompute.addMany(this.getCellsDependingOn(arrayFormulasPositionIds));
|
|
40876
40966
|
this.evaluate(cellsToCompute);
|
|
40877
40967
|
}
|
|
40878
40968
|
getArrayFormulasImpactedByChangesOf(positionIds) {
|
|
@@ -40886,7 +40976,7 @@ class Evaluator {
|
|
|
40886
40976
|
}
|
|
40887
40977
|
if (!content) {
|
|
40888
40978
|
// The previous content could have blocked some array formulas
|
|
40889
|
-
impactedPositionIds.
|
|
40979
|
+
impactedPositionIds.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(positionId));
|
|
40890
40980
|
}
|
|
40891
40981
|
}
|
|
40892
40982
|
return impactedPositionIds;
|
|
@@ -40935,7 +41025,7 @@ class Evaluator {
|
|
|
40935
41025
|
}
|
|
40936
41026
|
const arrayFormulas = this.spreadingRelations.getFormulaPositionsSpreadingOn(positionId);
|
|
40937
41027
|
const cells = new JetSet(arrayFormulas);
|
|
40938
|
-
cells.
|
|
41028
|
+
cells.addMany(this.getCellsDependingOn(arrayFormulas));
|
|
40939
41029
|
return cells;
|
|
40940
41030
|
}
|
|
40941
41031
|
nextPositionsToUpdate = new JetSet();
|
|
@@ -41084,7 +41174,7 @@ class Evaluator {
|
|
|
41084
41174
|
this.setEvaluatedCell(positionId, evaluatedCell);
|
|
41085
41175
|
// check if formula dependencies present in the spread zone
|
|
41086
41176
|
// if so, they need to be recomputed
|
|
41087
|
-
this.nextPositionsToUpdate.
|
|
41177
|
+
this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([positionId]));
|
|
41088
41178
|
};
|
|
41089
41179
|
}
|
|
41090
41180
|
invalidateSpreading(positionId) {
|
|
@@ -41099,8 +41189,8 @@ class Evaluator {
|
|
|
41099
41189
|
continue;
|
|
41100
41190
|
}
|
|
41101
41191
|
this.evaluatedCells.delete(child);
|
|
41102
|
-
this.nextPositionsToUpdate.
|
|
41103
|
-
this.nextPositionsToUpdate.
|
|
41192
|
+
this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([child]));
|
|
41193
|
+
this.nextPositionsToUpdate.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(child));
|
|
41104
41194
|
}
|
|
41105
41195
|
this.spreadingRelations.removeNode(positionId);
|
|
41106
41196
|
}
|
|
@@ -41449,7 +41539,13 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
41449
41539
|
const format = newFormat
|
|
41450
41540
|
? getItemId(newFormat, data.formats)
|
|
41451
41541
|
: exportedCellData.format;
|
|
41452
|
-
|
|
41542
|
+
let content;
|
|
41543
|
+
if (formulaCell instanceof FormulaCellWithDependencies) {
|
|
41544
|
+
content = this.getters.getFormulaCellContent(exportedSheetData.id, formulaCell.compiledFormula, formulaCell.compiledFormula.dependencies, true);
|
|
41545
|
+
}
|
|
41546
|
+
else {
|
|
41547
|
+
content = !isExported ? newContent : exportedCellData.content;
|
|
41548
|
+
}
|
|
41453
41549
|
exportedSheetData.cells[xc] = { ...exportedCellData, value, isFormula, content, format };
|
|
41454
41550
|
}
|
|
41455
41551
|
}
|
|
@@ -50765,6 +50861,16 @@ class ImageProvider {
|
|
|
50765
50861
|
}
|
|
50766
50862
|
}
|
|
50767
50863
|
|
|
50864
|
+
class FocusableElement {
|
|
50865
|
+
focusableElement = undefined;
|
|
50866
|
+
setFocusableElement(element) {
|
|
50867
|
+
this.focusableElement = element;
|
|
50868
|
+
}
|
|
50869
|
+
focus() {
|
|
50870
|
+
this.focusableElement?.focus();
|
|
50871
|
+
}
|
|
50872
|
+
}
|
|
50873
|
+
|
|
50768
50874
|
const RIPPLE_KEY_FRAMES = [
|
|
50769
50875
|
{ transform: "scale(0)" },
|
|
50770
50876
|
{ transform: "scale(0.8)", offset: 0.33 },
|
|
@@ -52921,6 +53027,7 @@ class Spreadsheet extends owl.Component {
|
|
|
52921
53027
|
toggleSidePanel: this.toggleSidePanel.bind(this),
|
|
52922
53028
|
clipboard: this.env.clipboard || instantiateClipboard(),
|
|
52923
53029
|
startCellEdition: (content) => this.onGridComposerCellFocused(content),
|
|
53030
|
+
focusableElement: new FocusableElement(),
|
|
52924
53031
|
});
|
|
52925
53032
|
owl.useExternalListener(window, "resize", () => this.render(true));
|
|
52926
53033
|
owl.useExternalListener(window, "beforeunload", this.unbindModelEvents.bind(this));
|
|
@@ -53027,16 +53134,17 @@ class Spreadsheet extends owl.Component {
|
|
|
53027
53134
|
}
|
|
53028
53135
|
this.composer.topBarFocus = "contentFocus";
|
|
53029
53136
|
this.composer.gridFocusMode = "inactive";
|
|
53030
|
-
this.setComposerContent({ selection }
|
|
53137
|
+
this.setComposerContent({ selection });
|
|
53031
53138
|
}
|
|
53032
|
-
onGridComposerContentFocused() {
|
|
53139
|
+
onGridComposerContentFocused(selection) {
|
|
53033
53140
|
if (this.model.getters.isReadonly()) {
|
|
53034
53141
|
return;
|
|
53035
53142
|
}
|
|
53036
53143
|
this.composer.topBarFocus = "inactive";
|
|
53037
53144
|
this.composer.gridFocusMode = "contentFocus";
|
|
53038
|
-
this.setComposerContent({});
|
|
53145
|
+
this.setComposerContent({ selection });
|
|
53039
53146
|
}
|
|
53147
|
+
// TODO: either both are defined or none of them. change those args to an object
|
|
53040
53148
|
onGridComposerCellFocused(content, selection) {
|
|
53041
53149
|
if (this.model.getters.isReadonly()) {
|
|
53042
53150
|
return;
|
|
@@ -54462,11 +54570,10 @@ class SelectionStreamProcessorImpl {
|
|
|
54462
54570
|
* next cluster if the given cell is outside a cluster or at the border of a cluster in the given direction.
|
|
54463
54571
|
*/
|
|
54464
54572
|
getEndOfCluster(startPosition, dim, dir) {
|
|
54465
|
-
const sheet = this.getters.getActiveSheet();
|
|
54466
54573
|
let currentPosition = startPosition;
|
|
54467
54574
|
// If both the current cell and the next cell are not empty, we want to go to the end of the cluster
|
|
54468
54575
|
const nextCellPosition = this.getNextCellPosition(startPosition, dim, dir);
|
|
54469
|
-
let mode = !this.
|
|
54576
|
+
let mode = !this.isEvaluatedCellEmpty(currentPosition) && !this.isEvaluatedCellEmpty(nextCellPosition)
|
|
54470
54577
|
? "endOfCluster"
|
|
54471
54578
|
: "nextCluster";
|
|
54472
54579
|
while (true) {
|
|
@@ -54476,7 +54583,7 @@ class SelectionStreamProcessorImpl {
|
|
|
54476
54583
|
currentPosition.row === nextCellPosition.row) {
|
|
54477
54584
|
break;
|
|
54478
54585
|
}
|
|
54479
|
-
const isNextCellEmpty = this.
|
|
54586
|
+
const isNextCellEmpty = this.isEvaluatedCellEmpty(nextCellPosition);
|
|
54480
54587
|
if (mode === "endOfCluster" && isNextCellEmpty) {
|
|
54481
54588
|
break;
|
|
54482
54589
|
}
|
|
@@ -54490,10 +54597,20 @@ class SelectionStreamProcessorImpl {
|
|
|
54490
54597
|
return dim === "cols" ? currentPosition.col : currentPosition.row;
|
|
54491
54598
|
}
|
|
54492
54599
|
/**
|
|
54493
|
-
*
|
|
54494
|
-
* check
|
|
54600
|
+
* Checks if a cell is empty (i.e. does not have a content). If the cell is part of a merge,
|
|
54601
|
+
* the check applies to the main cell of the merge.
|
|
54602
|
+
*/
|
|
54603
|
+
isCellEmpty({ col, row }) {
|
|
54604
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
54605
|
+
const position = this.getters.getMainCellPosition({ sheetId, col, row });
|
|
54606
|
+
return !(this.getters.getCorrespondingFormulaCell(position) || this.getters.getCell(position)?.content);
|
|
54607
|
+
}
|
|
54608
|
+
/**
|
|
54609
|
+
* Checks if a cell evaluated value is empty. If the cell is part of a merge,
|
|
54610
|
+
* the check applies to the main cell of the merge.
|
|
54495
54611
|
*/
|
|
54496
|
-
|
|
54612
|
+
isEvaluatedCellEmpty({ col, row }) {
|
|
54613
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
54497
54614
|
const position = this.getters.getMainCellPosition({ sheetId, col, row });
|
|
54498
54615
|
const cell = this.getters.getEvaluatedCell(position);
|
|
54499
54616
|
return cell.type === CellValueType.empty;
|
|
@@ -56799,6 +56916,6 @@ exports.setTranslationMethod = setTranslationMethod;
|
|
|
56799
56916
|
exports.tokenize = tokenize;
|
|
56800
56917
|
|
|
56801
56918
|
|
|
56802
|
-
__info__.version = "17.0.
|
|
56803
|
-
__info__.date = "2024-02-
|
|
56804
|
-
__info__.hash = "
|
|
56919
|
+
__info__.version = "17.0.12";
|
|
56920
|
+
__info__.date = "2024-02-16T14:24:02.984Z";
|
|
56921
|
+
__info__.hash = "8fa2bab";
|