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