@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
|
import { Component, useRef, onMounted, useEffect, onWillPatch, useState, onWillUpdateProps, onPatched, useComponent, useExternalListener, onWillUnmount, onWillStart, xml, useChildSubEnv, useSubEnv, markRaw } from '@odoo/owl';
|
|
@@ -550,8 +550,8 @@ function isObjectEmptyRecursive(argument) {
|
|
|
550
550
|
* If the given item does not exist in the dictionary, it creates one with a new id.
|
|
551
551
|
*/
|
|
552
552
|
function getItemId(item, itemsDic) {
|
|
553
|
-
for (
|
|
554
|
-
if (deepEquals(
|
|
553
|
+
for (const key in itemsDic) {
|
|
554
|
+
if (deepEquals(itemsDic[key], item)) {
|
|
555
555
|
return parseInt(key, 10);
|
|
556
556
|
}
|
|
557
557
|
}
|
|
@@ -650,11 +650,13 @@ function deepEquals(o1, o2) {
|
|
|
650
650
|
if (typeof o1 !== "object")
|
|
651
651
|
return o1 === o2;
|
|
652
652
|
// Objects can have different keys if the values are undefined
|
|
653
|
-
const
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
653
|
+
for (const key in o2) {
|
|
654
|
+
if (!(key in o1) && o2[key] !== undefined) {
|
|
655
|
+
return false;
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
for (const key in o1) {
|
|
659
|
+
if (typeof o1[key] !== typeof o2[key])
|
|
658
660
|
return false;
|
|
659
661
|
if (typeof o1[key] === "object") {
|
|
660
662
|
if (!deepEquals(o1[key], o2[key]))
|
|
@@ -724,18 +726,18 @@ function isConsecutive(iterable) {
|
|
|
724
726
|
return true;
|
|
725
727
|
}
|
|
726
728
|
class JetSet extends Set {
|
|
727
|
-
|
|
729
|
+
addMany(iterable) {
|
|
728
730
|
for (const element of iterable) {
|
|
729
731
|
super.add(element);
|
|
730
732
|
}
|
|
731
733
|
return this;
|
|
732
734
|
}
|
|
733
|
-
|
|
734
|
-
let
|
|
735
|
+
deleteMany(iterable) {
|
|
736
|
+
let wasDeleted = false;
|
|
735
737
|
for (const element of iterable) {
|
|
736
|
-
|
|
738
|
+
wasDeleted ||= super.delete(element);
|
|
737
739
|
}
|
|
738
|
-
return
|
|
740
|
+
return wasDeleted;
|
|
739
741
|
}
|
|
740
742
|
}
|
|
741
743
|
/**
|
|
@@ -1994,7 +1996,7 @@ class DispatchResult {
|
|
|
1994
1996
|
* Static helper which returns a successful DispatchResult
|
|
1995
1997
|
*/
|
|
1996
1998
|
static get Success() {
|
|
1997
|
-
return
|
|
1999
|
+
return SUCCESS;
|
|
1998
2000
|
}
|
|
1999
2001
|
get isSuccessful() {
|
|
2000
2002
|
return this.reasons.length === 0;
|
|
@@ -2007,6 +2009,7 @@ class DispatchResult {
|
|
|
2007
2009
|
return this.reasons.includes(reason);
|
|
2008
2010
|
}
|
|
2009
2011
|
}
|
|
2012
|
+
const SUCCESS = new DispatchResult();
|
|
2010
2013
|
var CommandResult;
|
|
2011
2014
|
(function (CommandResult) {
|
|
2012
2015
|
CommandResult["Success"] = "Success";
|
|
@@ -2888,6 +2891,9 @@ function parseFormat(formatString) {
|
|
|
2888
2891
|
function formatValue(value, { format, locale }) {
|
|
2889
2892
|
switch (typeof value) {
|
|
2890
2893
|
case "string":
|
|
2894
|
+
if (value.includes('\\"')) {
|
|
2895
|
+
return value.replace(/\\"/g, '"');
|
|
2896
|
+
}
|
|
2891
2897
|
return value;
|
|
2892
2898
|
case "boolean":
|
|
2893
2899
|
return value ? "TRUE" : "FALSE";
|
|
@@ -7379,7 +7385,7 @@ function tokenize(str, locale = DEFAULT_LOCALE) {
|
|
|
7379
7385
|
while (!chars.isOver()) {
|
|
7380
7386
|
let token = tokenizeSpace(chars) ||
|
|
7381
7387
|
tokenizeArgsSeparator(chars, locale) ||
|
|
7382
|
-
|
|
7388
|
+
tokenizeParenthesis(chars) ||
|
|
7383
7389
|
tokenizeOperator(chars) ||
|
|
7384
7390
|
tokenizeString(chars) ||
|
|
7385
7391
|
tokenizeDebugger(chars) ||
|
|
@@ -7400,15 +7406,14 @@ function tokenizeDebugger(chars) {
|
|
|
7400
7406
|
}
|
|
7401
7407
|
return null;
|
|
7402
7408
|
}
|
|
7403
|
-
const
|
|
7404
|
-
"(": "LEFT_PAREN",
|
|
7405
|
-
")": "RIGHT_PAREN",
|
|
7409
|
+
const parenthesis = {
|
|
7410
|
+
"(": { type: "LEFT_PAREN", value: "(" },
|
|
7411
|
+
")": { type: "RIGHT_PAREN", value: ")" },
|
|
7406
7412
|
};
|
|
7407
|
-
function
|
|
7408
|
-
if (chars.current
|
|
7413
|
+
function tokenizeParenthesis(chars) {
|
|
7414
|
+
if (chars.current === "(" || chars.current === ")") {
|
|
7409
7415
|
const value = chars.shift();
|
|
7410
|
-
|
|
7411
|
-
return { type, value };
|
|
7416
|
+
return parenthesis[value];
|
|
7412
7417
|
}
|
|
7413
7418
|
return null;
|
|
7414
7419
|
}
|
|
@@ -7429,7 +7434,12 @@ function tokenizeOperator(chars) {
|
|
|
7429
7434
|
}
|
|
7430
7435
|
return null;
|
|
7431
7436
|
}
|
|
7437
|
+
const FIRST_POSSIBLE_NUMBER_CHARS = new Set("0123456789");
|
|
7432
7438
|
function tokenizeNumber(chars, locale) {
|
|
7439
|
+
if (!FIRST_POSSIBLE_NUMBER_CHARS.has(chars.current) &&
|
|
7440
|
+
chars.current !== locale.decimalSeparator) {
|
|
7441
|
+
return null;
|
|
7442
|
+
}
|
|
7433
7443
|
const match = chars.remaining().match(getFormulaNumberRegex(locale.decimalSeparator));
|
|
7434
7444
|
if (match) {
|
|
7435
7445
|
chars.advanceBy(match[0].length);
|
|
@@ -7454,7 +7464,7 @@ function tokenizeString(chars) {
|
|
|
7454
7464
|
}
|
|
7455
7465
|
return null;
|
|
7456
7466
|
}
|
|
7457
|
-
const separatorRegexp =
|
|
7467
|
+
const separatorRegexp = /^[\w\.!\$]+/;
|
|
7458
7468
|
/**
|
|
7459
7469
|
* A "Symbol" is just basically any word-like element that can appear in a
|
|
7460
7470
|
* formula, which is not a string. So:
|
|
@@ -7494,8 +7504,11 @@ function tokenizeSymbol(chars) {
|
|
|
7494
7504
|
};
|
|
7495
7505
|
}
|
|
7496
7506
|
}
|
|
7497
|
-
|
|
7498
|
-
|
|
7507
|
+
const match = chars.remaining().match(separatorRegexp);
|
|
7508
|
+
if (match) {
|
|
7509
|
+
const value = match[0];
|
|
7510
|
+
result += value;
|
|
7511
|
+
chars.advanceBy(value.length);
|
|
7499
7512
|
}
|
|
7500
7513
|
if (result.length) {
|
|
7501
7514
|
const value = result;
|
|
@@ -7557,7 +7570,10 @@ class TokenizingChars {
|
|
|
7557
7570
|
return this.text.substring(this.currentIndex);
|
|
7558
7571
|
}
|
|
7559
7572
|
currentStartsWith(str) {
|
|
7560
|
-
|
|
7573
|
+
if (this.current !== str[0]) {
|
|
7574
|
+
return false;
|
|
7575
|
+
}
|
|
7576
|
+
for (let j = 1; j < str.length; j++) {
|
|
7561
7577
|
if (this.text[this.currentIndex + j] !== str[j]) {
|
|
7562
7578
|
return false;
|
|
7563
7579
|
}
|
|
@@ -7584,6 +7600,9 @@ function isValidLocale(locale) {
|
|
|
7584
7600
|
if (locale.formulaArgSeparator === locale.decimalSeparator) {
|
|
7585
7601
|
return false;
|
|
7586
7602
|
}
|
|
7603
|
+
if (locale.thousandsSeparator === locale.decimalSeparator) {
|
|
7604
|
+
return false;
|
|
7605
|
+
}
|
|
7587
7606
|
try {
|
|
7588
7607
|
formatValue(1, { locale, format: "#,##0.00" });
|
|
7589
7608
|
formatValue(1, { locale, format: locale.dateFormat });
|
|
@@ -7674,7 +7693,7 @@ function canonicalizeNumberLiteral(content, locale) {
|
|
|
7674
7693
|
if (locale.decimalSeparator === "." || !isNumber(content, locale)) {
|
|
7675
7694
|
return content;
|
|
7676
7695
|
}
|
|
7677
|
-
return content.replace(locale.decimalSeparator, ".");
|
|
7696
|
+
return content.replace(locale.thousandsSeparator, "").replace(locale.decimalSeparator, ".");
|
|
7678
7697
|
}
|
|
7679
7698
|
/**
|
|
7680
7699
|
* Change a content string from the given locale to its canonical form (en_US locale). Also convert date string.
|
|
@@ -10746,6 +10765,12 @@ const INSERT_LINK = (env) => {
|
|
|
10746
10765
|
let { col, row } = env.model.getters.getActivePosition();
|
|
10747
10766
|
env.model.dispatch("OPEN_CELL_POPOVER", { col, row, popoverType: "LinkEditor" });
|
|
10748
10767
|
};
|
|
10768
|
+
const INSERT_LINK_NAME = (env) => {
|
|
10769
|
+
const sheetId = env.model.getters.getActiveSheetId();
|
|
10770
|
+
const { col, row } = env.model.getters.getActivePosition();
|
|
10771
|
+
const cell = env.model.getters.getEvaluatedCell({ sheetId, col, row });
|
|
10772
|
+
return cell && cell.link ? _t("Edit link") : _t("Insert link");
|
|
10773
|
+
};
|
|
10749
10774
|
//------------------------------------------------------------------------------
|
|
10750
10775
|
// Filters action
|
|
10751
10776
|
//------------------------------------------------------------------------------
|
|
@@ -19777,7 +19802,7 @@ cellMenuRegistry
|
|
|
19777
19802
|
})
|
|
19778
19803
|
.add("insert_link", {
|
|
19779
19804
|
...insertLink,
|
|
19780
|
-
name:
|
|
19805
|
+
name: INSERT_LINK_NAME,
|
|
19781
19806
|
sequence: 150,
|
|
19782
19807
|
separator: true,
|
|
19783
19808
|
});
|
|
@@ -26030,6 +26055,17 @@ css /* scss */ `
|
|
|
26030
26055
|
`;
|
|
26031
26056
|
class TextValueProvider extends Component {
|
|
26032
26057
|
static template = "o-spreadsheet-TextValueProvider";
|
|
26058
|
+
autoCompleteListRef = useRef("autoCompleteList");
|
|
26059
|
+
setup() {
|
|
26060
|
+
useEffect(() => {
|
|
26061
|
+
const selectedIndex = this.props.selectedIndex;
|
|
26062
|
+
if (selectedIndex === undefined) {
|
|
26063
|
+
return;
|
|
26064
|
+
}
|
|
26065
|
+
const selectedElement = this.autoCompleteListRef.el?.children[selectedIndex];
|
|
26066
|
+
selectedElement?.scrollIntoView?.({ block: "nearest" });
|
|
26067
|
+
}, () => [this.props.selectedIndex, this.autoCompleteListRef.el]);
|
|
26068
|
+
}
|
|
26033
26069
|
}
|
|
26034
26070
|
TextValueProvider.props = {
|
|
26035
26071
|
values: Array,
|
|
@@ -26481,6 +26517,7 @@ css /* scss */ `
|
|
|
26481
26517
|
position: absolute;
|
|
26482
26518
|
margin: 1px 4px;
|
|
26483
26519
|
pointer-events: none;
|
|
26520
|
+
overflow: auto;
|
|
26484
26521
|
|
|
26485
26522
|
.o-semi-bold {
|
|
26486
26523
|
/** FIXME: to remove in favor of Bootstrap
|
|
@@ -26496,6 +26533,7 @@ class Composer extends Component {
|
|
|
26496
26533
|
static components = { TextValueProvider, FunctionDescriptionProvider };
|
|
26497
26534
|
static defaultProps = {
|
|
26498
26535
|
inputStyle: "",
|
|
26536
|
+
isDefaultFocus: false,
|
|
26499
26537
|
};
|
|
26500
26538
|
composerRef = useRef("o_composer");
|
|
26501
26539
|
contentHelper = new ContentEditableHelper(this.composerRef.el);
|
|
@@ -26526,7 +26564,10 @@ class Composer extends Component {
|
|
|
26526
26564
|
if (this.props.delimitation && this.props.rect) {
|
|
26527
26565
|
const { x: cellX, y: cellY, height: cellHeight } = this.props.rect;
|
|
26528
26566
|
const remainingHeight = this.props.delimitation.height - (cellY + cellHeight);
|
|
26567
|
+
assistantStyle["max-height"] = `${remainingHeight}px`;
|
|
26529
26568
|
if (cellY > remainingHeight) {
|
|
26569
|
+
const availableSpaceAbove = cellY;
|
|
26570
|
+
assistantStyle["max-height"] = `${availableSpaceAbove}px`;
|
|
26530
26571
|
// render top
|
|
26531
26572
|
// We compensate 2 px of margin on the assistant style + 1px for design reasons
|
|
26532
26573
|
assistantStyle.top = `-3px`;
|
|
@@ -26552,7 +26593,6 @@ class Composer extends Component {
|
|
|
26552
26593
|
F2: () => console.warn("Not implemented"),
|
|
26553
26594
|
F4: this.processF4Key,
|
|
26554
26595
|
Tab: (ev) => this.processTabKey(ev),
|
|
26555
|
-
" ": (ev) => this.processSpaceKey(ev),
|
|
26556
26596
|
};
|
|
26557
26597
|
keyCodeMapping = {
|
|
26558
26598
|
NumpadDecimal: this.processNumpadDecimal,
|
|
@@ -26560,12 +26600,12 @@ class Composer extends Component {
|
|
|
26560
26600
|
setup() {
|
|
26561
26601
|
onMounted(() => {
|
|
26562
26602
|
const el = this.composerRef.el;
|
|
26603
|
+
if (this.props.isDefaultFocus) {
|
|
26604
|
+
this.env.focusableElement.setFocusableElement(el);
|
|
26605
|
+
}
|
|
26563
26606
|
this.contentHelper.updateEl(el);
|
|
26564
26607
|
this.processTokenAtCursor();
|
|
26565
26608
|
});
|
|
26566
|
-
onWillUnmount(() => {
|
|
26567
|
-
this.props.onComposerUnmounted?.();
|
|
26568
|
-
});
|
|
26569
26609
|
useEffect(() => {
|
|
26570
26610
|
this.processContent();
|
|
26571
26611
|
});
|
|
@@ -26574,7 +26614,8 @@ class Composer extends Component {
|
|
|
26574
26614
|
// Handlers
|
|
26575
26615
|
// ---------------------------------------------------------------------------
|
|
26576
26616
|
processArrowKeys(ev) {
|
|
26577
|
-
if (this.env.model.getters.isSelectingForComposer()
|
|
26617
|
+
if (this.env.model.getters.isSelectingForComposer() ||
|
|
26618
|
+
this.env.model.getters.getEditionMode() === "inactive") {
|
|
26578
26619
|
this.functionDescriptionState.showDescription = false;
|
|
26579
26620
|
// Prevent the default content editable behavior which moves the cursor
|
|
26580
26621
|
ev.preventDefault();
|
|
@@ -26617,26 +26658,20 @@ class Composer extends Component {
|
|
|
26617
26658
|
processTabKey(ev) {
|
|
26618
26659
|
ev.preventDefault();
|
|
26619
26660
|
ev.stopPropagation();
|
|
26620
|
-
|
|
26621
|
-
|
|
26622
|
-
|
|
26623
|
-
|
|
26624
|
-
|
|
26625
|
-
|
|
26661
|
+
if (this.env.model.getters.getEditionMode() !== "inactive") {
|
|
26662
|
+
const state = this.autoCompleteState;
|
|
26663
|
+
if (state.showProvider && state.selectedIndex !== undefined) {
|
|
26664
|
+
const autoCompleteValue = this.autoCompleteState.values[state.selectedIndex]?.text;
|
|
26665
|
+
if (autoCompleteValue) {
|
|
26666
|
+
this.autoComplete(autoCompleteValue);
|
|
26667
|
+
return;
|
|
26668
|
+
}
|
|
26626
26669
|
}
|
|
26670
|
+
interactiveStopEdition(this.env);
|
|
26627
26671
|
}
|
|
26628
26672
|
const direction = ev.shiftKey ? "left" : "right";
|
|
26629
|
-
interactiveStopEdition(this.env);
|
|
26630
26673
|
this.env.model.selection.moveAnchorCell(direction, 1);
|
|
26631
26674
|
}
|
|
26632
|
-
processSpaceKey(ev) {
|
|
26633
|
-
if (ev.ctrlKey) {
|
|
26634
|
-
ev.preventDefault();
|
|
26635
|
-
ev.stopPropagation();
|
|
26636
|
-
this.showFunctionAutocomplete("");
|
|
26637
|
-
this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
|
|
26638
|
-
}
|
|
26639
|
-
}
|
|
26640
26675
|
processEnterKey(ev) {
|
|
26641
26676
|
ev.preventDefault();
|
|
26642
26677
|
ev.stopPropagation();
|
|
@@ -26689,6 +26724,9 @@ class Composer extends Component {
|
|
|
26689
26724
|
this.compositionActive = false;
|
|
26690
26725
|
}
|
|
26691
26726
|
onKeydown(ev) {
|
|
26727
|
+
if (this.env.model.getters.getEditionMode() === "inactive") {
|
|
26728
|
+
return;
|
|
26729
|
+
}
|
|
26692
26730
|
let handler = this.keyMapping[ev.key] || this.keyCodeMapping[ev.code];
|
|
26693
26731
|
if (handler) {
|
|
26694
26732
|
handler.call(this, ev);
|
|
@@ -26697,14 +26735,33 @@ class Composer extends Component {
|
|
|
26697
26735
|
ev.stopPropagation();
|
|
26698
26736
|
}
|
|
26699
26737
|
}
|
|
26738
|
+
onPaste(ev) {
|
|
26739
|
+
if (this.env.model.getters.getEditionMode() !== "inactive") {
|
|
26740
|
+
ev.stopPropagation();
|
|
26741
|
+
}
|
|
26742
|
+
}
|
|
26700
26743
|
/*
|
|
26701
26744
|
* Triggered automatically by the content-editable between the keydown and key up
|
|
26702
26745
|
* */
|
|
26703
26746
|
onInput(ev) {
|
|
26704
|
-
if (
|
|
26747
|
+
if (!this.shouldProcessInputEvents) {
|
|
26705
26748
|
return;
|
|
26706
26749
|
}
|
|
26707
|
-
|
|
26750
|
+
if (ev.inputType === "insertFromPaste" &&
|
|
26751
|
+
this.env.model.getters.getEditionMode() === "inactive") {
|
|
26752
|
+
return;
|
|
26753
|
+
}
|
|
26754
|
+
ev.stopPropagation();
|
|
26755
|
+
let content;
|
|
26756
|
+
if (this.env.model.getters.getEditionMode() === "inactive") {
|
|
26757
|
+
content = ev.data || "";
|
|
26758
|
+
}
|
|
26759
|
+
else {
|
|
26760
|
+
content = this.contentHelper.getText();
|
|
26761
|
+
}
|
|
26762
|
+
if (this.props.focus === "inactive") {
|
|
26763
|
+
return this.props.onComposerCellFocused?.(content);
|
|
26764
|
+
}
|
|
26708
26765
|
let selection = this.contentHelper.getCurrentSelection();
|
|
26709
26766
|
if (ev.inputType === "insertParagraph") {
|
|
26710
26767
|
const start = Math.min(selection.start, selection.end);
|
|
@@ -26786,9 +26843,8 @@ class Composer extends Component {
|
|
|
26786
26843
|
}
|
|
26787
26844
|
const newSelection = this.contentHelper.getCurrentSelection();
|
|
26788
26845
|
this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
|
|
26789
|
-
|
|
26790
|
-
|
|
26791
|
-
}
|
|
26846
|
+
this.props.onComposerContentFocused();
|
|
26847
|
+
if (this.props.focus === "inactive") ;
|
|
26792
26848
|
this.env.model.dispatch("CHANGE_COMPOSER_CURSOR_SELECTION", newSelection);
|
|
26793
26849
|
this.processTokenAtCursor();
|
|
26794
26850
|
}
|
|
@@ -26955,7 +27011,7 @@ class Composer extends Component {
|
|
|
26955
27011
|
const highlights = this.env.model.getters.getHighlights();
|
|
26956
27012
|
const refSheet = sheetName
|
|
26957
27013
|
? this.env.model.getters.getSheetIdByName(sheetName)
|
|
26958
|
-
: this.env.model.getters.getCurrentEditedCell()
|
|
27014
|
+
: this.env.model.getters.getCurrentEditedCell()?.sheetId;
|
|
26959
27015
|
const highlight = highlights.find((highlight) => {
|
|
26960
27016
|
if (highlight.sheetId !== refSheet)
|
|
26961
27017
|
return false;
|
|
@@ -27048,12 +27104,13 @@ class Composer extends Component {
|
|
|
27048
27104
|
}
|
|
27049
27105
|
}
|
|
27050
27106
|
Composer.props = {
|
|
27051
|
-
focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
|
|
27052
|
-
onComposerContentFocused: Function,
|
|
27053
27107
|
inputStyle: { type: String, optional: true },
|
|
27054
27108
|
rect: { type: Object, optional: true },
|
|
27055
27109
|
delimitation: { type: Object, optional: true },
|
|
27056
|
-
|
|
27110
|
+
focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
|
|
27111
|
+
onComposerCellFocused: { type: Function, optional: true },
|
|
27112
|
+
onComposerContentFocused: Function,
|
|
27113
|
+
isDefaultFocus: { type: Boolean, optional: true },
|
|
27057
27114
|
};
|
|
27058
27115
|
|
|
27059
27116
|
const COMPOSER_BORDER_WIDTH = 3 * 0.4 * window.devicePixelRatio || 1;
|
|
@@ -27087,51 +27144,25 @@ css /* scss */ `
|
|
|
27087
27144
|
class GridComposer extends Component {
|
|
27088
27145
|
static template = "o-spreadsheet-GridComposer";
|
|
27089
27146
|
static components = { Composer };
|
|
27090
|
-
|
|
27091
|
-
|
|
27092
|
-
rect;
|
|
27147
|
+
rect = this.defaultRect;
|
|
27148
|
+
isEditing = false;
|
|
27093
27149
|
isCellReferenceVisible;
|
|
27094
|
-
|
|
27150
|
+
get defaultRect() {
|
|
27151
|
+
return { x: 0, y: 0, width: 0, height: 0 };
|
|
27152
|
+
}
|
|
27095
27153
|
setup() {
|
|
27096
|
-
this.gridComposerRef = useRef("gridComposer");
|
|
27097
|
-
this.composerState = useState({
|
|
27098
|
-
rect: undefined,
|
|
27099
|
-
delimitation: undefined,
|
|
27100
|
-
});
|
|
27101
|
-
const { sheetId, col, row } = this.env.model.getters.getActivePosition();
|
|
27102
|
-
this.zone = this.env.model.getters.expandZone(sheetId, positionToZone({ col, row }));
|
|
27103
|
-
this.rect = this.env.model.getters.getVisibleRect(this.zone);
|
|
27104
|
-
this.isCellReferenceVisible = false;
|
|
27105
|
-
onMounted(() => {
|
|
27106
|
-
const el = this.gridComposerRef.el;
|
|
27107
|
-
this.composerState.rect = {
|
|
27108
|
-
x: this.rect.x,
|
|
27109
|
-
y: this.rect.y,
|
|
27110
|
-
width: el.clientWidth,
|
|
27111
|
-
height: el.clientHeight,
|
|
27112
|
-
};
|
|
27113
|
-
this.composerState.delimitation = {
|
|
27114
|
-
width: this.props.gridDims.width,
|
|
27115
|
-
height: this.props.gridDims.height,
|
|
27116
|
-
};
|
|
27117
|
-
});
|
|
27118
27154
|
onWillUpdateProps(() => {
|
|
27119
|
-
|
|
27120
|
-
|
|
27121
|
-
}
|
|
27122
|
-
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
27123
|
-
const zone = this.env.model.getters.getSelectedZone();
|
|
27124
|
-
const rect = this.env.model.getters.getVisibleRect(zone);
|
|
27125
|
-
if (!deepEquals(rect, this.rect) ||
|
|
27126
|
-
sheetId !== this.env.model.getters.getCurrentEditedCell().sheetId) {
|
|
27127
|
-
this.isCellReferenceVisible = true;
|
|
27128
|
-
}
|
|
27155
|
+
this.updateComponentPosition();
|
|
27156
|
+
this.updateCellReferenceVisibility();
|
|
27129
27157
|
});
|
|
27130
27158
|
}
|
|
27131
27159
|
get shouldDisplayCellReference() {
|
|
27132
27160
|
return this.isCellReferenceVisible;
|
|
27133
27161
|
}
|
|
27134
27162
|
get cellReference() {
|
|
27163
|
+
if (!this.env.model.getters.getCurrentEditedCell()) {
|
|
27164
|
+
return "";
|
|
27165
|
+
}
|
|
27135
27166
|
const { col, row, sheetId } = this.env.model.getters.getCurrentEditedCell();
|
|
27136
27167
|
const prefixSheet = sheetId !== this.env.model.getters.getActiveSheetId();
|
|
27137
27168
|
return `${prefixSheet ? getCanonicalSheetName(this.env.model.getters.getSheetName(sheetId)) + "!" : ""}${toXC(col, row)}`;
|
|
@@ -27143,7 +27174,27 @@ class GridComposer extends Component {
|
|
|
27143
27174
|
top: `${top - GRID_CELL_REFERENCE_TOP_OFFSET}px`,
|
|
27144
27175
|
});
|
|
27145
27176
|
}
|
|
27177
|
+
get composerProps() {
|
|
27178
|
+
const { width, height } = this.env.model.getters.getSheetViewDimensionWithHeaders();
|
|
27179
|
+
return {
|
|
27180
|
+
rect: { ...this.rect },
|
|
27181
|
+
delimitation: {
|
|
27182
|
+
width,
|
|
27183
|
+
height,
|
|
27184
|
+
},
|
|
27185
|
+
focus: this.props.focus,
|
|
27186
|
+
isDefaultFocus: true,
|
|
27187
|
+
onComposerContentFocused: this.props.onComposerContentFocused,
|
|
27188
|
+
onComposerCellFocused: this.props.onComposerCellFocused,
|
|
27189
|
+
};
|
|
27190
|
+
}
|
|
27146
27191
|
get containerStyle() {
|
|
27192
|
+
if (this.env.model.getters.getEditionMode() === "inactive" || !this.rect) {
|
|
27193
|
+
return `
|
|
27194
|
+
position: absolute;
|
|
27195
|
+
z-index: -1000;
|
|
27196
|
+
`;
|
|
27197
|
+
}
|
|
27147
27198
|
const isFormula = this.env.model.getters.getCurrentContent().startsWith("=");
|
|
27148
27199
|
const cell = this.env.model.getters.getActiveCell();
|
|
27149
27200
|
const position = this.env.model.getters.getActivePosition();
|
|
@@ -27163,6 +27214,8 @@ class GridComposer extends Component {
|
|
|
27163
27214
|
if (!isFormula) {
|
|
27164
27215
|
textAlign = style.align || cell.defaultAlign;
|
|
27165
27216
|
}
|
|
27217
|
+
const maxHeight = this.props.gridDims.height - this.rect.y;
|
|
27218
|
+
const maxWidth = this.props.gridDims.width - this.rect.x;
|
|
27166
27219
|
/**
|
|
27167
27220
|
* min-size is on the container, not the composer element, because we want to have the same size as the cell by default,
|
|
27168
27221
|
* including all the paddings/margins of the composer
|
|
@@ -27174,6 +27227,8 @@ class GridComposer extends Component {
|
|
|
27174
27227
|
top: `${top}px`,
|
|
27175
27228
|
"min-width": `${width + 1}px`,
|
|
27176
27229
|
"min-height": `${height + 1}px`,
|
|
27230
|
+
"max-width": `${maxWidth}px`,
|
|
27231
|
+
"max-height": `${maxHeight}px`,
|
|
27177
27232
|
background,
|
|
27178
27233
|
color,
|
|
27179
27234
|
"font-size": `${fontSizeInPixels(fontSize)}px`,
|
|
@@ -27183,20 +27238,38 @@ class GridComposer extends Component {
|
|
|
27183
27238
|
"text-align": textAlign,
|
|
27184
27239
|
});
|
|
27185
27240
|
}
|
|
27186
|
-
|
|
27187
|
-
const
|
|
27188
|
-
|
|
27189
|
-
|
|
27190
|
-
|
|
27191
|
-
|
|
27192
|
-
|
|
27241
|
+
updateComponentPosition() {
|
|
27242
|
+
const isEditing = this.env.model.getters.getEditionMode() !== "inactive";
|
|
27243
|
+
if (this.isEditing !== isEditing) {
|
|
27244
|
+
this.isEditing = isEditing;
|
|
27245
|
+
if (!isEditing) {
|
|
27246
|
+
this.rect = this.defaultRect;
|
|
27247
|
+
this.env.focusableElement.focus();
|
|
27248
|
+
return;
|
|
27249
|
+
}
|
|
27250
|
+
const position = this.env.model.getters.getActivePosition();
|
|
27251
|
+
const zone = this.env.model.getters.expandZone(position.sheetId, positionToZone(position));
|
|
27252
|
+
this.rect = this.env.model.getters.getVisibleRect(zone);
|
|
27253
|
+
}
|
|
27254
|
+
}
|
|
27255
|
+
updateCellReferenceVisibility() {
|
|
27256
|
+
if (this.isCellReferenceVisible || this.env.model.getters.getEditionMode() === "inactive") {
|
|
27257
|
+
return;
|
|
27258
|
+
}
|
|
27259
|
+
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
27260
|
+
const zone = this.env.model.getters.getSelectedZone();
|
|
27261
|
+
const rect = this.env.model.getters.getVisibleRect(zone);
|
|
27262
|
+
if (!deepEquals(rect, this.rect) ||
|
|
27263
|
+
sheetId !== this.env.model.getters.getCurrentEditedCell().sheetId) {
|
|
27264
|
+
this.isCellReferenceVisible = true;
|
|
27265
|
+
}
|
|
27193
27266
|
}
|
|
27194
27267
|
}
|
|
27195
27268
|
GridComposer.props = {
|
|
27196
27269
|
focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
|
|
27197
|
-
onComposerUnmounted: Function,
|
|
27198
27270
|
onComposerContentFocused: Function,
|
|
27199
27271
|
gridDims: Object,
|
|
27272
|
+
onComposerCellFocused: Function,
|
|
27200
27273
|
};
|
|
27201
27274
|
|
|
27202
27275
|
const CSS$1 = css /* scss */ `
|
|
@@ -28287,7 +28360,6 @@ class GridOverlay extends Component {
|
|
|
28287
28360
|
this.props.onCellDoubleClicked(col, row);
|
|
28288
28361
|
}
|
|
28289
28362
|
onContextMenu(ev) {
|
|
28290
|
-
ev.preventDefault();
|
|
28291
28363
|
const [col, row] = this.getCartesianCoordinates(ev);
|
|
28292
28364
|
this.props.onCellRightClicked(col, row, { x: ev.clientX, y: ev.clientY });
|
|
28293
28365
|
}
|
|
@@ -29372,7 +29444,6 @@ class Grid extends Component {
|
|
|
29372
29444
|
HEADER_WIDTH = HEADER_WIDTH;
|
|
29373
29445
|
menuState;
|
|
29374
29446
|
gridRef;
|
|
29375
|
-
hiddenInput;
|
|
29376
29447
|
onMouseWheel;
|
|
29377
29448
|
canvasPosition;
|
|
29378
29449
|
hoveredCell;
|
|
@@ -29383,17 +29454,16 @@ class Grid extends Component {
|
|
|
29383
29454
|
menuItems: [],
|
|
29384
29455
|
});
|
|
29385
29456
|
this.gridRef = useRef("grid");
|
|
29386
|
-
this.hiddenInput = useRef("hiddenInput");
|
|
29387
29457
|
this.canvasPosition = useAbsoluteBoundingRect(this.gridRef);
|
|
29388
29458
|
this.hoveredCell = useState({ col: undefined, row: undefined });
|
|
29389
29459
|
useChildSubEnv({ getPopoverContainerRect: () => this.getGridRect() });
|
|
29390
29460
|
useExternalListener(document.body, "cut", this.copy.bind(this, true));
|
|
29391
29461
|
useExternalListener(document.body, "copy", this.copy.bind(this, false));
|
|
29392
29462
|
useExternalListener(document.body, "paste", this.paste);
|
|
29393
|
-
onMounted(() => this.
|
|
29394
|
-
this.props.exposeFocus(() => this.
|
|
29463
|
+
onMounted(() => this.focusDefaultElement());
|
|
29464
|
+
this.props.exposeFocus(() => this.focusDefaultElement());
|
|
29395
29465
|
useGridDrawing("canvas", this.env.model, () => this.env.model.getters.getSheetViewDimensionWithHeaders());
|
|
29396
|
-
useEffect(() => this.
|
|
29466
|
+
useEffect(() => this.focusDefaultElement(), () => [this.env.model.getters.getActiveSheetId()]);
|
|
29397
29467
|
this.onMouseWheel = useWheelHandler((deltaX, deltaY) => {
|
|
29398
29468
|
this.moveCanvas(deltaX, deltaY);
|
|
29399
29469
|
this.hoveredCell.col = undefined;
|
|
@@ -29416,7 +29486,7 @@ class Grid extends Component {
|
|
|
29416
29486
|
if (this.env.model.getters.hasOpenedPopover()) {
|
|
29417
29487
|
this.closeOpenedPopover();
|
|
29418
29488
|
}
|
|
29419
|
-
this.
|
|
29489
|
+
this.focusDefaultElement();
|
|
29420
29490
|
}
|
|
29421
29491
|
// this map will handle most of the actions that should happen on key down. The arrow keys are managed in the key
|
|
29422
29492
|
// down itself
|
|
@@ -29595,10 +29665,10 @@ class Grid extends Component {
|
|
|
29595
29665
|
"ALT+SHIFT+ARROWUP": () => this.processHeaderGroupingKey("up"),
|
|
29596
29666
|
"ALT+SHIFT+ARROWDOWN": () => this.processHeaderGroupingKey("down"),
|
|
29597
29667
|
};
|
|
29598
|
-
|
|
29668
|
+
focusDefaultElement() {
|
|
29599
29669
|
if (!this.env.model.getters.getSelectedFigureId() &&
|
|
29600
29670
|
this.env.model.getters.getEditionMode() === "inactive") {
|
|
29601
|
-
this.
|
|
29671
|
+
this.env.focusableElement.focus();
|
|
29602
29672
|
}
|
|
29603
29673
|
}
|
|
29604
29674
|
get gridEl() {
|
|
@@ -29743,19 +29813,6 @@ class Grid extends Component {
|
|
|
29743
29813
|
return;
|
|
29744
29814
|
}
|
|
29745
29815
|
}
|
|
29746
|
-
onInput(ev) {
|
|
29747
|
-
// the user meant to paste in the sheet, not open the composer with the pasted content
|
|
29748
|
-
if (!ev.isComposing && ev.inputType === "insertFromPaste") {
|
|
29749
|
-
return;
|
|
29750
|
-
}
|
|
29751
|
-
if (ev.data) {
|
|
29752
|
-
// if the user types a character on the grid, it means he wants to start composing the selected cell with that
|
|
29753
|
-
// character
|
|
29754
|
-
ev.preventDefault();
|
|
29755
|
-
ev.stopPropagation();
|
|
29756
|
-
this.props.onGridComposerCellFocused(ev.data);
|
|
29757
|
-
}
|
|
29758
|
-
}
|
|
29759
29816
|
// ---------------------------------------------------------------------------
|
|
29760
29817
|
// Context Menu
|
|
29761
29818
|
// ---------------------------------------------------------------------------
|
|
@@ -29870,7 +29927,7 @@ class Grid extends Component {
|
|
|
29870
29927
|
}
|
|
29871
29928
|
closeMenu() {
|
|
29872
29929
|
this.menuState.isOpen = false;
|
|
29873
|
-
this.
|
|
29930
|
+
this.focusDefaultElement();
|
|
29874
29931
|
}
|
|
29875
29932
|
processHeaderGroupingKey(direction) {
|
|
29876
29933
|
if (this.env.model.getters.getSelectedZones().length !== 1) {
|
|
@@ -33765,6 +33822,31 @@ const MIGRATIONS = [
|
|
|
33765
33822
|
return data;
|
|
33766
33823
|
},
|
|
33767
33824
|
},
|
|
33825
|
+
{
|
|
33826
|
+
description: "Fix datafilter duplication",
|
|
33827
|
+
from: 12,
|
|
33828
|
+
to: 12.5,
|
|
33829
|
+
applyMigration(data) {
|
|
33830
|
+
for (let sheet of data.sheets || []) {
|
|
33831
|
+
let knownDataFilterZones = [];
|
|
33832
|
+
for (let filterTable of sheet.filterTables || []) {
|
|
33833
|
+
const zone = toZone(filterTable.range);
|
|
33834
|
+
// See commit message for the details
|
|
33835
|
+
const intersectZoneIndex = knownDataFilterZones.findIndex((knownZone) => overlap(knownZone, zone));
|
|
33836
|
+
if (intersectZoneIndex !== -1) {
|
|
33837
|
+
knownDataFilterZones[intersectZoneIndex] = zone;
|
|
33838
|
+
}
|
|
33839
|
+
else {
|
|
33840
|
+
knownDataFilterZones.push(zone);
|
|
33841
|
+
}
|
|
33842
|
+
}
|
|
33843
|
+
sheet.filterTables = knownDataFilterZones.map((zone) => ({
|
|
33844
|
+
range: zoneToXc(zone),
|
|
33845
|
+
}));
|
|
33846
|
+
}
|
|
33847
|
+
return data;
|
|
33848
|
+
},
|
|
33849
|
+
},
|
|
33768
33850
|
{
|
|
33769
33851
|
description: "Change Border description structure",
|
|
33770
33852
|
from: 12,
|
|
@@ -34604,22 +34686,7 @@ class BordersPlugin extends CorePlugin {
|
|
|
34604
34686
|
}
|
|
34605
34687
|
}
|
|
34606
34688
|
export(data) {
|
|
34607
|
-
// Borders
|
|
34608
|
-
let borderId = 0;
|
|
34609
34689
|
const borders = {};
|
|
34610
|
-
/**
|
|
34611
|
-
* Get the id of the given border. If the border does not exist, it creates
|
|
34612
|
-
* one.
|
|
34613
|
-
*/
|
|
34614
|
-
function getBorderId(border) {
|
|
34615
|
-
for (let [key, value] of Object.entries(borders)) {
|
|
34616
|
-
if (deepEquals(value, border)) {
|
|
34617
|
-
return parseInt(key, 10);
|
|
34618
|
-
}
|
|
34619
|
-
}
|
|
34620
|
-
borders[++borderId] = border;
|
|
34621
|
-
return borderId;
|
|
34622
|
-
}
|
|
34623
34690
|
for (let sheet of data.sheets) {
|
|
34624
34691
|
for (let col = 0; col < sheet.colNumber; col++) {
|
|
34625
34692
|
for (let row = 0; row < sheet.rowNumber; row++) {
|
|
@@ -34627,7 +34694,7 @@ class BordersPlugin extends CorePlugin {
|
|
|
34627
34694
|
if (border) {
|
|
34628
34695
|
const xc = toXC(col, row);
|
|
34629
34696
|
const cell = sheet.cells[xc];
|
|
34630
|
-
const borderId =
|
|
34697
|
+
const borderId = getItemId(border, borders);
|
|
34631
34698
|
if (cell) {
|
|
34632
34699
|
cell.border = borderId;
|
|
34633
34700
|
}
|
|
@@ -35432,9 +35499,9 @@ class CellPlugin extends CorePlugin {
|
|
|
35432
35499
|
allowDispatch(cmd) {
|
|
35433
35500
|
switch (cmd.type) {
|
|
35434
35501
|
case "UPDATE_CELL":
|
|
35435
|
-
return this.
|
|
35502
|
+
return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessUpdateCell);
|
|
35436
35503
|
case "CLEAR_CELL":
|
|
35437
|
-
return this.checkValidations(cmd, this.
|
|
35504
|
+
return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessClearCell);
|
|
35438
35505
|
default:
|
|
35439
35506
|
return "Success" /* CommandResult.Success */;
|
|
35440
35507
|
}
|
|
@@ -35567,9 +35634,6 @@ class CellPlugin extends CorePlugin {
|
|
|
35567
35634
|
format: cell.format ? getItemId(cell.format, formats) : undefined,
|
|
35568
35635
|
content: cell.content || undefined,
|
|
35569
35636
|
};
|
|
35570
|
-
if (cell instanceof FormulaCellWithDependencies) {
|
|
35571
|
-
cells[xc].content = cell.contentWithFixedReferences || undefined;
|
|
35572
|
-
}
|
|
35573
35637
|
}
|
|
35574
35638
|
_sheet.cells = cells;
|
|
35575
35639
|
}
|
|
@@ -35587,8 +35651,8 @@ class CellPlugin extends CorePlugin {
|
|
|
35587
35651
|
}
|
|
35588
35652
|
removeDefaultStyleValues(style) {
|
|
35589
35653
|
const cleanedStyle = { ...style };
|
|
35590
|
-
for (const
|
|
35591
|
-
if (cleanedStyle[property] ===
|
|
35654
|
+
for (const property in DEFAULT_STYLE) {
|
|
35655
|
+
if (cleanedStyle[property] === DEFAULT_STYLE[property]) {
|
|
35592
35656
|
delete cleanedStyle[property];
|
|
35593
35657
|
}
|
|
35594
35658
|
}
|
|
@@ -35745,10 +35809,7 @@ class CellPlugin extends CorePlugin {
|
|
|
35745
35809
|
else {
|
|
35746
35810
|
style = before ? before.style : undefined;
|
|
35747
35811
|
}
|
|
35748
|
-
const
|
|
35749
|
-
let format = ("format" in after ? after.format : before && before.format) ||
|
|
35750
|
-
detectDateFormat(afterContent, locale) ||
|
|
35751
|
-
detectNumberFormat(afterContent);
|
|
35812
|
+
const format = "format" in after ? after.format : before && before.format;
|
|
35752
35813
|
/* Read the following IF as:
|
|
35753
35814
|
* we need to remove the cell if it is completely empty, but we can know if it completely empty if:
|
|
35754
35815
|
* - the command says the new content is empty and has no border/format/style
|
|
@@ -35789,12 +35850,11 @@ class CellPlugin extends CorePlugin {
|
|
|
35789
35850
|
}
|
|
35790
35851
|
createLiteralCell(id, content, format, style) {
|
|
35791
35852
|
const locale = this.getters.getLocale();
|
|
35792
|
-
content = parseLiteral(content, locale).toString();
|
|
35793
35853
|
return {
|
|
35794
35854
|
id,
|
|
35795
|
-
content,
|
|
35855
|
+
content: parseLiteral(content, locale).toString(),
|
|
35796
35856
|
style,
|
|
35797
|
-
format,
|
|
35857
|
+
format: format || detectDateFormat(content, locale) || detectNumberFormat(content),
|
|
35798
35858
|
isFormula: false,
|
|
35799
35859
|
};
|
|
35800
35860
|
}
|
|
@@ -35820,8 +35880,11 @@ class CellPlugin extends CorePlugin {
|
|
|
35820
35880
|
* being a computed property to rebuild the dependencies XC.
|
|
35821
35881
|
*/
|
|
35822
35882
|
createFormulaCellWithDependencies(id, compiledFormula, format, style, sheetId) {
|
|
35823
|
-
const dependencies =
|
|
35824
|
-
|
|
35883
|
+
const dependencies = [];
|
|
35884
|
+
for (const xc of compiledFormula.dependencies) {
|
|
35885
|
+
dependencies.push(this.getters.getRangeFromSheetXC(sheetId, xc));
|
|
35886
|
+
}
|
|
35887
|
+
return new FormulaCellWithDependencies(id, compiledFormula, format, style, dependencies, sheetId, this.getters.getRangeString);
|
|
35825
35888
|
}
|
|
35826
35889
|
createErrorFormula(id, content, format, style, error) {
|
|
35827
35890
|
return {
|
|
@@ -35856,6 +35919,18 @@ class CellPlugin extends CorePlugin {
|
|
|
35856
35919
|
}
|
|
35857
35920
|
return "Success" /* CommandResult.Success */;
|
|
35858
35921
|
}
|
|
35922
|
+
checkUselessUpdateCell(cmd) {
|
|
35923
|
+
const cell = this.getters.getCell(cmd);
|
|
35924
|
+
const hasContent = "content" in cmd || "formula" in cmd;
|
|
35925
|
+
const hasStyle = "style" in cmd;
|
|
35926
|
+
const hasFormat = "format" in cmd;
|
|
35927
|
+
if ((!hasContent || cell?.content === cmd.content) &&
|
|
35928
|
+
(!hasStyle || deepEquals(cell?.style, cmd.style)) &&
|
|
35929
|
+
(!hasFormat || cell?.format === cmd.format)) {
|
|
35930
|
+
return "NoChanges" /* CommandResult.NoChanges */;
|
|
35931
|
+
}
|
|
35932
|
+
return "Success" /* CommandResult.Success */;
|
|
35933
|
+
}
|
|
35859
35934
|
}
|
|
35860
35935
|
class FormulaCellWithDependencies {
|
|
35861
35936
|
id;
|
|
@@ -35875,7 +35950,7 @@ class FormulaCellWithDependencies {
|
|
|
35875
35950
|
const tokens = compiledFormula.tokens.map((token) => {
|
|
35876
35951
|
if (token.type === "REFERENCE") {
|
|
35877
35952
|
const index = rangeIndex++;
|
|
35878
|
-
return new RangeReferenceToken(
|
|
35953
|
+
return new RangeReferenceToken(dependencies, index, this.sheetId, this.getRangeString);
|
|
35879
35954
|
}
|
|
35880
35955
|
return token;
|
|
35881
35956
|
});
|
|
@@ -35902,13 +35977,20 @@ class FormulaCellWithDependencies {
|
|
|
35902
35977
|
}
|
|
35903
35978
|
}
|
|
35904
35979
|
class RangeReferenceToken {
|
|
35905
|
-
|
|
35980
|
+
ranges;
|
|
35981
|
+
rangeIndex;
|
|
35982
|
+
sheetId;
|
|
35983
|
+
getRangeString;
|
|
35906
35984
|
type = "REFERENCE";
|
|
35907
|
-
constructor(
|
|
35908
|
-
this.
|
|
35985
|
+
constructor(ranges, rangeIndex, sheetId, getRangeString) {
|
|
35986
|
+
this.ranges = ranges;
|
|
35987
|
+
this.rangeIndex = rangeIndex;
|
|
35988
|
+
this.sheetId = sheetId;
|
|
35989
|
+
this.getRangeString = getRangeString;
|
|
35909
35990
|
}
|
|
35910
35991
|
get value() {
|
|
35911
|
-
|
|
35992
|
+
const range = this.ranges[this.rangeIndex];
|
|
35993
|
+
return this.getRangeString(range, this.sheetId);
|
|
35912
35994
|
}
|
|
35913
35995
|
}
|
|
35914
35996
|
|
|
@@ -40644,7 +40726,15 @@ class SpreadsheetRTree {
|
|
|
40644
40726
|
if (!this.rTrees[sheetId]) {
|
|
40645
40727
|
return;
|
|
40646
40728
|
}
|
|
40647
|
-
this.rTrees[sheetId].remove(item,
|
|
40729
|
+
this.rTrees[sheetId].remove(item, this.rtreeItemComparer);
|
|
40730
|
+
}
|
|
40731
|
+
rtreeItemComparer(left, right) {
|
|
40732
|
+
return (left.data == right.data &&
|
|
40733
|
+
left.boundingBox.sheetId === right.boundingBox.sheetId &&
|
|
40734
|
+
left.boundingBox?.zone.left === right.boundingBox.zone.left &&
|
|
40735
|
+
left.boundingBox?.zone.top === right.boundingBox.zone.top &&
|
|
40736
|
+
left.boundingBox?.zone.right === right.boundingBox.zone.right &&
|
|
40737
|
+
left.boundingBox?.zone.bottom === right.boundingBox.zone.bottom);
|
|
40648
40738
|
}
|
|
40649
40739
|
}
|
|
40650
40740
|
/**
|
|
@@ -40722,7 +40812,7 @@ class FormulaDependencyGraph {
|
|
|
40722
40812
|
const queue = Array.from(ranges).reverse();
|
|
40723
40813
|
while (queue.length > 0) {
|
|
40724
40814
|
const range = queue.pop();
|
|
40725
|
-
visited.
|
|
40815
|
+
visited.addMany(this.encoder.encodeBoundingBox(range));
|
|
40726
40816
|
const impactedPositionIds = this.rTree.search(range).map((dep) => dep.data);
|
|
40727
40817
|
for (const positionId of impactedPositionIds) {
|
|
40728
40818
|
if (!visited.has(positionId)) {
|
|
@@ -40730,7 +40820,7 @@ class FormulaDependencyGraph {
|
|
|
40730
40820
|
}
|
|
40731
40821
|
}
|
|
40732
40822
|
}
|
|
40733
|
-
visited.
|
|
40823
|
+
visited.deleteMany(ranges.flatMap((r) => this.encoder.encodeBoundingBox(r)));
|
|
40734
40824
|
return visited;
|
|
40735
40825
|
}
|
|
40736
40826
|
}
|
|
@@ -40868,9 +40958,9 @@ class Evaluator {
|
|
|
40868
40958
|
const cells = positions.map((p) => this.encoder.encode(p));
|
|
40869
40959
|
const cellsToCompute = new JetSet(cells);
|
|
40870
40960
|
const arrayFormulasPositionIds = this.getArrayFormulasImpactedByChangesOf(cells);
|
|
40871
|
-
cellsToCompute.
|
|
40872
|
-
cellsToCompute.
|
|
40873
|
-
cellsToCompute.
|
|
40961
|
+
cellsToCompute.addMany(this.getCellsDependingOn(cells));
|
|
40962
|
+
cellsToCompute.addMany(arrayFormulasPositionIds);
|
|
40963
|
+
cellsToCompute.addMany(this.getCellsDependingOn(arrayFormulasPositionIds));
|
|
40874
40964
|
this.evaluate(cellsToCompute);
|
|
40875
40965
|
}
|
|
40876
40966
|
getArrayFormulasImpactedByChangesOf(positionIds) {
|
|
@@ -40884,7 +40974,7 @@ class Evaluator {
|
|
|
40884
40974
|
}
|
|
40885
40975
|
if (!content) {
|
|
40886
40976
|
// The previous content could have blocked some array formulas
|
|
40887
|
-
impactedPositionIds.
|
|
40977
|
+
impactedPositionIds.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(positionId));
|
|
40888
40978
|
}
|
|
40889
40979
|
}
|
|
40890
40980
|
return impactedPositionIds;
|
|
@@ -40933,7 +41023,7 @@ class Evaluator {
|
|
|
40933
41023
|
}
|
|
40934
41024
|
const arrayFormulas = this.spreadingRelations.getFormulaPositionsSpreadingOn(positionId);
|
|
40935
41025
|
const cells = new JetSet(arrayFormulas);
|
|
40936
|
-
cells.
|
|
41026
|
+
cells.addMany(this.getCellsDependingOn(arrayFormulas));
|
|
40937
41027
|
return cells;
|
|
40938
41028
|
}
|
|
40939
41029
|
nextPositionsToUpdate = new JetSet();
|
|
@@ -41082,7 +41172,7 @@ class Evaluator {
|
|
|
41082
41172
|
this.setEvaluatedCell(positionId, evaluatedCell);
|
|
41083
41173
|
// check if formula dependencies present in the spread zone
|
|
41084
41174
|
// if so, they need to be recomputed
|
|
41085
|
-
this.nextPositionsToUpdate.
|
|
41175
|
+
this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([positionId]));
|
|
41086
41176
|
};
|
|
41087
41177
|
}
|
|
41088
41178
|
invalidateSpreading(positionId) {
|
|
@@ -41097,8 +41187,8 @@ class Evaluator {
|
|
|
41097
41187
|
continue;
|
|
41098
41188
|
}
|
|
41099
41189
|
this.evaluatedCells.delete(child);
|
|
41100
|
-
this.nextPositionsToUpdate.
|
|
41101
|
-
this.nextPositionsToUpdate.
|
|
41190
|
+
this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([child]));
|
|
41191
|
+
this.nextPositionsToUpdate.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(child));
|
|
41102
41192
|
}
|
|
41103
41193
|
this.spreadingRelations.removeNode(positionId);
|
|
41104
41194
|
}
|
|
@@ -41447,7 +41537,13 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
41447
41537
|
const format = newFormat
|
|
41448
41538
|
? getItemId(newFormat, data.formats)
|
|
41449
41539
|
: exportedCellData.format;
|
|
41450
|
-
|
|
41540
|
+
let content;
|
|
41541
|
+
if (formulaCell instanceof FormulaCellWithDependencies) {
|
|
41542
|
+
content = this.getters.getFormulaCellContent(exportedSheetData.id, formulaCell.compiledFormula, formulaCell.compiledFormula.dependencies, true);
|
|
41543
|
+
}
|
|
41544
|
+
else {
|
|
41545
|
+
content = !isExported ? newContent : exportedCellData.content;
|
|
41546
|
+
}
|
|
41451
41547
|
exportedSheetData.cells[xc] = { ...exportedCellData, value, isFormula, content, format };
|
|
41452
41548
|
}
|
|
41453
41549
|
}
|
|
@@ -50763,6 +50859,16 @@ class ImageProvider {
|
|
|
50763
50859
|
}
|
|
50764
50860
|
}
|
|
50765
50861
|
|
|
50862
|
+
class FocusableElement {
|
|
50863
|
+
focusableElement = undefined;
|
|
50864
|
+
setFocusableElement(element) {
|
|
50865
|
+
this.focusableElement = element;
|
|
50866
|
+
}
|
|
50867
|
+
focus() {
|
|
50868
|
+
this.focusableElement?.focus();
|
|
50869
|
+
}
|
|
50870
|
+
}
|
|
50871
|
+
|
|
50766
50872
|
const RIPPLE_KEY_FRAMES = [
|
|
50767
50873
|
{ transform: "scale(0)" },
|
|
50768
50874
|
{ transform: "scale(0.8)", offset: 0.33 },
|
|
@@ -52919,6 +53025,7 @@ class Spreadsheet extends Component {
|
|
|
52919
53025
|
toggleSidePanel: this.toggleSidePanel.bind(this),
|
|
52920
53026
|
clipboard: this.env.clipboard || instantiateClipboard(),
|
|
52921
53027
|
startCellEdition: (content) => this.onGridComposerCellFocused(content),
|
|
53028
|
+
focusableElement: new FocusableElement(),
|
|
52922
53029
|
});
|
|
52923
53030
|
useExternalListener(window, "resize", () => this.render(true));
|
|
52924
53031
|
useExternalListener(window, "beforeunload", this.unbindModelEvents.bind(this));
|
|
@@ -53025,16 +53132,17 @@ class Spreadsheet extends Component {
|
|
|
53025
53132
|
}
|
|
53026
53133
|
this.composer.topBarFocus = "contentFocus";
|
|
53027
53134
|
this.composer.gridFocusMode = "inactive";
|
|
53028
|
-
this.setComposerContent({ selection }
|
|
53135
|
+
this.setComposerContent({ selection });
|
|
53029
53136
|
}
|
|
53030
|
-
onGridComposerContentFocused() {
|
|
53137
|
+
onGridComposerContentFocused(selection) {
|
|
53031
53138
|
if (this.model.getters.isReadonly()) {
|
|
53032
53139
|
return;
|
|
53033
53140
|
}
|
|
53034
53141
|
this.composer.topBarFocus = "inactive";
|
|
53035
53142
|
this.composer.gridFocusMode = "contentFocus";
|
|
53036
|
-
this.setComposerContent({});
|
|
53143
|
+
this.setComposerContent({ selection });
|
|
53037
53144
|
}
|
|
53145
|
+
// TODO: either both are defined or none of them. change those args to an object
|
|
53038
53146
|
onGridComposerCellFocused(content, selection) {
|
|
53039
53147
|
if (this.model.getters.isReadonly()) {
|
|
53040
53148
|
return;
|
|
@@ -54460,11 +54568,10 @@ class SelectionStreamProcessorImpl {
|
|
|
54460
54568
|
* next cluster if the given cell is outside a cluster or at the border of a cluster in the given direction.
|
|
54461
54569
|
*/
|
|
54462
54570
|
getEndOfCluster(startPosition, dim, dir) {
|
|
54463
|
-
const sheet = this.getters.getActiveSheet();
|
|
54464
54571
|
let currentPosition = startPosition;
|
|
54465
54572
|
// If both the current cell and the next cell are not empty, we want to go to the end of the cluster
|
|
54466
54573
|
const nextCellPosition = this.getNextCellPosition(startPosition, dim, dir);
|
|
54467
|
-
let mode = !this.
|
|
54574
|
+
let mode = !this.isEvaluatedCellEmpty(currentPosition) && !this.isEvaluatedCellEmpty(nextCellPosition)
|
|
54468
54575
|
? "endOfCluster"
|
|
54469
54576
|
: "nextCluster";
|
|
54470
54577
|
while (true) {
|
|
@@ -54474,7 +54581,7 @@ class SelectionStreamProcessorImpl {
|
|
|
54474
54581
|
currentPosition.row === nextCellPosition.row) {
|
|
54475
54582
|
break;
|
|
54476
54583
|
}
|
|
54477
|
-
const isNextCellEmpty = this.
|
|
54584
|
+
const isNextCellEmpty = this.isEvaluatedCellEmpty(nextCellPosition);
|
|
54478
54585
|
if (mode === "endOfCluster" && isNextCellEmpty) {
|
|
54479
54586
|
break;
|
|
54480
54587
|
}
|
|
@@ -54488,10 +54595,20 @@ class SelectionStreamProcessorImpl {
|
|
|
54488
54595
|
return dim === "cols" ? currentPosition.col : currentPosition.row;
|
|
54489
54596
|
}
|
|
54490
54597
|
/**
|
|
54491
|
-
*
|
|
54492
|
-
* check
|
|
54598
|
+
* Checks if a cell is empty (i.e. does not have a content). If the cell is part of a merge,
|
|
54599
|
+
* the check applies to the main cell of the merge.
|
|
54600
|
+
*/
|
|
54601
|
+
isCellEmpty({ col, row }) {
|
|
54602
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
54603
|
+
const position = this.getters.getMainCellPosition({ sheetId, col, row });
|
|
54604
|
+
return !(this.getters.getCorrespondingFormulaCell(position) || this.getters.getCell(position)?.content);
|
|
54605
|
+
}
|
|
54606
|
+
/**
|
|
54607
|
+
* Checks if a cell evaluated value is empty. If the cell is part of a merge,
|
|
54608
|
+
* the check applies to the main cell of the merge.
|
|
54493
54609
|
*/
|
|
54494
|
-
|
|
54610
|
+
isEvaluatedCellEmpty({ col, row }) {
|
|
54611
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
54495
54612
|
const position = this.getters.getMainCellPosition({ sheetId, col, row });
|
|
54496
54613
|
const cell = this.getters.getEvaluatedCell(position);
|
|
54497
54614
|
return cell.type === CellValueType.empty;
|
|
@@ -56762,6 +56879,6 @@ const constants = {
|
|
|
56762
56879
|
export { AbstractChart, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, tokenize };
|
|
56763
56880
|
|
|
56764
56881
|
|
|
56765
|
-
__info__.version = "17.0.
|
|
56766
|
-
__info__.date = "2024-02-
|
|
56767
|
-
__info__.hash = "
|
|
56882
|
+
__info__.version = "17.0.12";
|
|
56883
|
+
__info__.date = "2024-02-16T14:24:02.984Z";
|
|
56884
|
+
__info__.hash = "8fa2bab";
|