@odoo/o-spreadsheet 17.0.9 → 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 +363 -232
- package/dist/o-spreadsheet.d.ts +39 -18
- package/dist/o-spreadsheet.esm.js +363 -232
- package/dist/o-spreadsheet.iife.js +363 -232
- package/dist/o-spreadsheet.iife.min.js +262 -268
- 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-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 17.0.12
|
|
6
|
+
* @date 2024-02-16T14:24:02.984Z
|
|
7
|
+
* @hash 8fa2bab
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
'use strict';
|
|
@@ -552,8 +552,8 @@ function isObjectEmptyRecursive(argument) {
|
|
|
552
552
|
* If the given item does not exist in the dictionary, it creates one with a new id.
|
|
553
553
|
*/
|
|
554
554
|
function getItemId(item, itemsDic) {
|
|
555
|
-
for (
|
|
556
|
-
if (deepEquals(
|
|
555
|
+
for (const key in itemsDic) {
|
|
556
|
+
if (deepEquals(itemsDic[key], item)) {
|
|
557
557
|
return parseInt(key, 10);
|
|
558
558
|
}
|
|
559
559
|
}
|
|
@@ -652,11 +652,13 @@ function deepEquals(o1, o2) {
|
|
|
652
652
|
if (typeof o1 !== "object")
|
|
653
653
|
return o1 === o2;
|
|
654
654
|
// Objects can have different keys if the values are undefined
|
|
655
|
-
const
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
655
|
+
for (const key in o2) {
|
|
656
|
+
if (!(key in o1) && o2[key] !== undefined) {
|
|
657
|
+
return false;
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
for (const key in o1) {
|
|
661
|
+
if (typeof o1[key] !== typeof o2[key])
|
|
660
662
|
return false;
|
|
661
663
|
if (typeof o1[key] === "object") {
|
|
662
664
|
if (!deepEquals(o1[key], o2[key]))
|
|
@@ -726,18 +728,18 @@ function isConsecutive(iterable) {
|
|
|
726
728
|
return true;
|
|
727
729
|
}
|
|
728
730
|
class JetSet extends Set {
|
|
729
|
-
|
|
731
|
+
addMany(iterable) {
|
|
730
732
|
for (const element of iterable) {
|
|
731
733
|
super.add(element);
|
|
732
734
|
}
|
|
733
735
|
return this;
|
|
734
736
|
}
|
|
735
|
-
|
|
736
|
-
let
|
|
737
|
+
deleteMany(iterable) {
|
|
738
|
+
let wasDeleted = false;
|
|
737
739
|
for (const element of iterable) {
|
|
738
|
-
|
|
740
|
+
wasDeleted ||= super.delete(element);
|
|
739
741
|
}
|
|
740
|
-
return
|
|
742
|
+
return wasDeleted;
|
|
741
743
|
}
|
|
742
744
|
}
|
|
743
745
|
/**
|
|
@@ -1996,7 +1998,7 @@ class DispatchResult {
|
|
|
1996
1998
|
* Static helper which returns a successful DispatchResult
|
|
1997
1999
|
*/
|
|
1998
2000
|
static get Success() {
|
|
1999
|
-
return
|
|
2001
|
+
return SUCCESS;
|
|
2000
2002
|
}
|
|
2001
2003
|
get isSuccessful() {
|
|
2002
2004
|
return this.reasons.length === 0;
|
|
@@ -2009,6 +2011,7 @@ class DispatchResult {
|
|
|
2009
2011
|
return this.reasons.includes(reason);
|
|
2010
2012
|
}
|
|
2011
2013
|
}
|
|
2014
|
+
const SUCCESS = new DispatchResult();
|
|
2012
2015
|
exports.CommandResult = void 0;
|
|
2013
2016
|
(function (CommandResult) {
|
|
2014
2017
|
CommandResult["Success"] = "Success";
|
|
@@ -2890,6 +2893,9 @@ function parseFormat(formatString) {
|
|
|
2890
2893
|
function formatValue(value, { format, locale }) {
|
|
2891
2894
|
switch (typeof value) {
|
|
2892
2895
|
case "string":
|
|
2896
|
+
if (value.includes('\\"')) {
|
|
2897
|
+
return value.replace(/\\"/g, '"');
|
|
2898
|
+
}
|
|
2893
2899
|
return value;
|
|
2894
2900
|
case "boolean":
|
|
2895
2901
|
return value ? "TRUE" : "FALSE";
|
|
@@ -4934,14 +4940,8 @@ function createDataSets(getters, dataSetsString, sheetId, dataSetsHaveTitle) {
|
|
|
4934
4940
|
: undefined));
|
|
4935
4941
|
}
|
|
4936
4942
|
}
|
|
4937
|
-
else if (zone.left === zone.right && zone.top === zone.bottom) {
|
|
4938
|
-
// A single cell. If it's only the title, the dataset is not added.
|
|
4939
|
-
if (!dataSetsHaveTitle) {
|
|
4940
|
-
dataSets.push(createDataSet(getters, dataSetSheetId, zone, undefined));
|
|
4941
|
-
}
|
|
4942
|
-
}
|
|
4943
4943
|
else {
|
|
4944
|
-
/* 1 row or 1 column */
|
|
4944
|
+
/* 1 cell, 1 row or 1 column */
|
|
4945
4945
|
dataSets.push(createDataSet(getters, dataSetSheetId, zone, dataSetsHaveTitle
|
|
4946
4946
|
? {
|
|
4947
4947
|
top: zone.top,
|
|
@@ -4990,8 +4990,10 @@ function toExcelDataset(getters, ds) {
|
|
|
4990
4990
|
}
|
|
4991
4991
|
const dataRange = ds.dataRange.clone({ zone: dataZone });
|
|
4992
4992
|
return {
|
|
4993
|
-
label: ds.labelCell
|
|
4994
|
-
|
|
4993
|
+
label: ds.labelCell
|
|
4994
|
+
? getters.getRangeString(ds.labelCell, "forceSheetReference", { useFixedReference: true })
|
|
4995
|
+
: undefined,
|
|
4996
|
+
range: getters.getRangeString(dataRange, "forceSheetReference", { useFixedReference: true }),
|
|
4995
4997
|
};
|
|
4996
4998
|
}
|
|
4997
4999
|
function toExcelLabelRange(getters, labelRange, shouldRemoveFirstLabel) {
|
|
@@ -5004,7 +5006,7 @@ function toExcelLabelRange(getters, labelRange, shouldRemoveFirstLabel) {
|
|
|
5004
5006
|
zone.top = zone.top + 1;
|
|
5005
5007
|
}
|
|
5006
5008
|
const range = labelRange.clone({ zone });
|
|
5007
|
-
return getters.getRangeString(range, "forceSheetReference");
|
|
5009
|
+
return getters.getRangeString(range, "forceSheetReference", { useFixedReference: true });
|
|
5008
5010
|
}
|
|
5009
5011
|
/**
|
|
5010
5012
|
* Transform a chart definition which supports dataSets (dataSets and LabelRange)
|
|
@@ -7385,7 +7387,7 @@ function tokenize(str, locale = DEFAULT_LOCALE) {
|
|
|
7385
7387
|
while (!chars.isOver()) {
|
|
7386
7388
|
let token = tokenizeSpace(chars) ||
|
|
7387
7389
|
tokenizeArgsSeparator(chars, locale) ||
|
|
7388
|
-
|
|
7390
|
+
tokenizeParenthesis(chars) ||
|
|
7389
7391
|
tokenizeOperator(chars) ||
|
|
7390
7392
|
tokenizeString(chars) ||
|
|
7391
7393
|
tokenizeDebugger(chars) ||
|
|
@@ -7406,15 +7408,14 @@ function tokenizeDebugger(chars) {
|
|
|
7406
7408
|
}
|
|
7407
7409
|
return null;
|
|
7408
7410
|
}
|
|
7409
|
-
const
|
|
7410
|
-
"(": "LEFT_PAREN",
|
|
7411
|
-
")": "RIGHT_PAREN",
|
|
7411
|
+
const parenthesis = {
|
|
7412
|
+
"(": { type: "LEFT_PAREN", value: "(" },
|
|
7413
|
+
")": { type: "RIGHT_PAREN", value: ")" },
|
|
7412
7414
|
};
|
|
7413
|
-
function
|
|
7414
|
-
if (chars.current
|
|
7415
|
+
function tokenizeParenthesis(chars) {
|
|
7416
|
+
if (chars.current === "(" || chars.current === ")") {
|
|
7415
7417
|
const value = chars.shift();
|
|
7416
|
-
|
|
7417
|
-
return { type, value };
|
|
7418
|
+
return parenthesis[value];
|
|
7418
7419
|
}
|
|
7419
7420
|
return null;
|
|
7420
7421
|
}
|
|
@@ -7435,7 +7436,12 @@ function tokenizeOperator(chars) {
|
|
|
7435
7436
|
}
|
|
7436
7437
|
return null;
|
|
7437
7438
|
}
|
|
7439
|
+
const FIRST_POSSIBLE_NUMBER_CHARS = new Set("0123456789");
|
|
7438
7440
|
function tokenizeNumber(chars, locale) {
|
|
7441
|
+
if (!FIRST_POSSIBLE_NUMBER_CHARS.has(chars.current) &&
|
|
7442
|
+
chars.current !== locale.decimalSeparator) {
|
|
7443
|
+
return null;
|
|
7444
|
+
}
|
|
7439
7445
|
const match = chars.remaining().match(getFormulaNumberRegex(locale.decimalSeparator));
|
|
7440
7446
|
if (match) {
|
|
7441
7447
|
chars.advanceBy(match[0].length);
|
|
@@ -7460,7 +7466,7 @@ function tokenizeString(chars) {
|
|
|
7460
7466
|
}
|
|
7461
7467
|
return null;
|
|
7462
7468
|
}
|
|
7463
|
-
const separatorRegexp =
|
|
7469
|
+
const separatorRegexp = /^[\w\.!\$]+/;
|
|
7464
7470
|
/**
|
|
7465
7471
|
* A "Symbol" is just basically any word-like element that can appear in a
|
|
7466
7472
|
* formula, which is not a string. So:
|
|
@@ -7500,8 +7506,11 @@ function tokenizeSymbol(chars) {
|
|
|
7500
7506
|
};
|
|
7501
7507
|
}
|
|
7502
7508
|
}
|
|
7503
|
-
|
|
7504
|
-
|
|
7509
|
+
const match = chars.remaining().match(separatorRegexp);
|
|
7510
|
+
if (match) {
|
|
7511
|
+
const value = match[0];
|
|
7512
|
+
result += value;
|
|
7513
|
+
chars.advanceBy(value.length);
|
|
7505
7514
|
}
|
|
7506
7515
|
if (result.length) {
|
|
7507
7516
|
const value = result;
|
|
@@ -7563,7 +7572,10 @@ class TokenizingChars {
|
|
|
7563
7572
|
return this.text.substring(this.currentIndex);
|
|
7564
7573
|
}
|
|
7565
7574
|
currentStartsWith(str) {
|
|
7566
|
-
|
|
7575
|
+
if (this.current !== str[0]) {
|
|
7576
|
+
return false;
|
|
7577
|
+
}
|
|
7578
|
+
for (let j = 1; j < str.length; j++) {
|
|
7567
7579
|
if (this.text[this.currentIndex + j] !== str[j]) {
|
|
7568
7580
|
return false;
|
|
7569
7581
|
}
|
|
@@ -7590,6 +7602,9 @@ function isValidLocale(locale) {
|
|
|
7590
7602
|
if (locale.formulaArgSeparator === locale.decimalSeparator) {
|
|
7591
7603
|
return false;
|
|
7592
7604
|
}
|
|
7605
|
+
if (locale.thousandsSeparator === locale.decimalSeparator) {
|
|
7606
|
+
return false;
|
|
7607
|
+
}
|
|
7593
7608
|
try {
|
|
7594
7609
|
formatValue(1, { locale, format: "#,##0.00" });
|
|
7595
7610
|
formatValue(1, { locale, format: locale.dateFormat });
|
|
@@ -7680,7 +7695,7 @@ function canonicalizeNumberLiteral(content, locale) {
|
|
|
7680
7695
|
if (locale.decimalSeparator === "." || !isNumber(content, locale)) {
|
|
7681
7696
|
return content;
|
|
7682
7697
|
}
|
|
7683
|
-
return content.replace(locale.decimalSeparator, ".");
|
|
7698
|
+
return content.replace(locale.thousandsSeparator, "").replace(locale.decimalSeparator, ".");
|
|
7684
7699
|
}
|
|
7685
7700
|
/**
|
|
7686
7701
|
* Change a content string from the given locale to its canonical form (en_US locale). Also convert date string.
|
|
@@ -8594,7 +8609,7 @@ class BarChart extends AbstractChart {
|
|
|
8594
8609
|
return undefined;
|
|
8595
8610
|
const dataSets = this.dataSets
|
|
8596
8611
|
.map((ds) => toExcelDataset(this.getters, ds))
|
|
8597
|
-
.filter((ds) => ds.range !== ""
|
|
8612
|
+
.filter((ds) => ds.range !== "" && ds.range !== INCORRECT_RANGE_STRING);
|
|
8598
8613
|
const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
8599
8614
|
return {
|
|
8600
8615
|
...this.getDefinition(),
|
|
@@ -9172,7 +9187,7 @@ class LineChart extends AbstractChart {
|
|
|
9172
9187
|
return undefined;
|
|
9173
9188
|
const dataSets = this.dataSets
|
|
9174
9189
|
.map((ds) => toExcelDataset(this.getters, ds))
|
|
9175
|
-
.filter((ds) => ds.range !== ""
|
|
9190
|
+
.filter((ds) => ds.range !== "" && ds.range !== INCORRECT_RANGE_STRING);
|
|
9176
9191
|
const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
9177
9192
|
return {
|
|
9178
9193
|
...this.getDefinition(),
|
|
@@ -9478,7 +9493,7 @@ class PieChart extends AbstractChart {
|
|
|
9478
9493
|
return undefined;
|
|
9479
9494
|
const dataSets = this.dataSets
|
|
9480
9495
|
.map((ds) => toExcelDataset(this.getters, ds))
|
|
9481
|
-
.filter((ds) => ds.range !== ""
|
|
9496
|
+
.filter((ds) => ds.range !== "" && ds.range !== INCORRECT_RANGE_STRING);
|
|
9482
9497
|
const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
9483
9498
|
return {
|
|
9484
9499
|
...this.getDefinition(),
|
|
@@ -10752,6 +10767,12 @@ const INSERT_LINK = (env) => {
|
|
|
10752
10767
|
let { col, row } = env.model.getters.getActivePosition();
|
|
10753
10768
|
env.model.dispatch("OPEN_CELL_POPOVER", { col, row, popoverType: "LinkEditor" });
|
|
10754
10769
|
};
|
|
10770
|
+
const INSERT_LINK_NAME = (env) => {
|
|
10771
|
+
const sheetId = env.model.getters.getActiveSheetId();
|
|
10772
|
+
const { col, row } = env.model.getters.getActivePosition();
|
|
10773
|
+
const cell = env.model.getters.getEvaluatedCell({ sheetId, col, row });
|
|
10774
|
+
return cell && cell.link ? _t("Edit link") : _t("Insert link");
|
|
10775
|
+
};
|
|
10755
10776
|
//------------------------------------------------------------------------------
|
|
10756
10777
|
// Filters action
|
|
10757
10778
|
//------------------------------------------------------------------------------
|
|
@@ -19783,7 +19804,7 @@ cellMenuRegistry
|
|
|
19783
19804
|
})
|
|
19784
19805
|
.add("insert_link", {
|
|
19785
19806
|
...insertLink,
|
|
19786
|
-
name:
|
|
19807
|
+
name: INSERT_LINK_NAME,
|
|
19787
19808
|
sequence: 150,
|
|
19788
19809
|
separator: true,
|
|
19789
19810
|
});
|
|
@@ -19921,19 +19942,20 @@ const formatNumberPercent = createFormatActionSpec({
|
|
|
19921
19942
|
const formatNumberCurrency = createFormatActionSpec({
|
|
19922
19943
|
name: _t("Currency"),
|
|
19923
19944
|
descriptionValue: 1000.12,
|
|
19924
|
-
format: (env) => env.model.config.defaultCurrencyFormat,
|
|
19945
|
+
format: (env) => env.model.config.defaultCurrencyFormat ?? DEFAULT_CURRENCY_FORMAT,
|
|
19925
19946
|
});
|
|
19926
19947
|
const formatNumberCurrencyRounded = {
|
|
19927
19948
|
...createFormatActionSpec({
|
|
19928
19949
|
name: _t("Currency rounded"),
|
|
19929
19950
|
descriptionValue: 1000,
|
|
19930
|
-
format: (env) => roundFormat(env.model.config.defaultCurrencyFormat),
|
|
19951
|
+
format: (env) => roundFormat(env.model.config.defaultCurrencyFormat ?? DEFAULT_CURRENCY_FORMAT),
|
|
19931
19952
|
}),
|
|
19932
19953
|
isVisible: (env) => {
|
|
19933
19954
|
const currencyFormat = env.model.config.defaultCurrencyFormat;
|
|
19934
|
-
return currencyFormat !== roundFormat(currencyFormat);
|
|
19955
|
+
return currencyFormat !== roundFormat(currencyFormat ?? DEFAULT_CURRENCY_FORMAT);
|
|
19935
19956
|
},
|
|
19936
19957
|
};
|
|
19958
|
+
const DEFAULT_CURRENCY_FORMAT = "[$$]#,##0.00";
|
|
19937
19959
|
const EXAMPLE_DATE = parseLiteral("2023/09/26 10:43:00 PM", DEFAULT_LOCALE);
|
|
19938
19960
|
const formatCustomCurrency = {
|
|
19939
19961
|
name: _t("Custom currency"),
|
|
@@ -26035,6 +26057,17 @@ css /* scss */ `
|
|
|
26035
26057
|
`;
|
|
26036
26058
|
class TextValueProvider extends owl.Component {
|
|
26037
26059
|
static template = "o-spreadsheet-TextValueProvider";
|
|
26060
|
+
autoCompleteListRef = owl.useRef("autoCompleteList");
|
|
26061
|
+
setup() {
|
|
26062
|
+
owl.useEffect(() => {
|
|
26063
|
+
const selectedIndex = this.props.selectedIndex;
|
|
26064
|
+
if (selectedIndex === undefined) {
|
|
26065
|
+
return;
|
|
26066
|
+
}
|
|
26067
|
+
const selectedElement = this.autoCompleteListRef.el?.children[selectedIndex];
|
|
26068
|
+
selectedElement?.scrollIntoView?.({ block: "nearest" });
|
|
26069
|
+
}, () => [this.props.selectedIndex, this.autoCompleteListRef.el]);
|
|
26070
|
+
}
|
|
26038
26071
|
}
|
|
26039
26072
|
TextValueProvider.props = {
|
|
26040
26073
|
values: Array,
|
|
@@ -26486,6 +26519,7 @@ css /* scss */ `
|
|
|
26486
26519
|
position: absolute;
|
|
26487
26520
|
margin: 1px 4px;
|
|
26488
26521
|
pointer-events: none;
|
|
26522
|
+
overflow: auto;
|
|
26489
26523
|
|
|
26490
26524
|
.o-semi-bold {
|
|
26491
26525
|
/** FIXME: to remove in favor of Bootstrap
|
|
@@ -26501,6 +26535,7 @@ class Composer extends owl.Component {
|
|
|
26501
26535
|
static components = { TextValueProvider, FunctionDescriptionProvider };
|
|
26502
26536
|
static defaultProps = {
|
|
26503
26537
|
inputStyle: "",
|
|
26538
|
+
isDefaultFocus: false,
|
|
26504
26539
|
};
|
|
26505
26540
|
composerRef = owl.useRef("o_composer");
|
|
26506
26541
|
contentHelper = new ContentEditableHelper(this.composerRef.el);
|
|
@@ -26531,7 +26566,10 @@ class Composer extends owl.Component {
|
|
|
26531
26566
|
if (this.props.delimitation && this.props.rect) {
|
|
26532
26567
|
const { x: cellX, y: cellY, height: cellHeight } = this.props.rect;
|
|
26533
26568
|
const remainingHeight = this.props.delimitation.height - (cellY + cellHeight);
|
|
26569
|
+
assistantStyle["max-height"] = `${remainingHeight}px`;
|
|
26534
26570
|
if (cellY > remainingHeight) {
|
|
26571
|
+
const availableSpaceAbove = cellY;
|
|
26572
|
+
assistantStyle["max-height"] = `${availableSpaceAbove}px`;
|
|
26535
26573
|
// render top
|
|
26536
26574
|
// We compensate 2 px of margin on the assistant style + 1px for design reasons
|
|
26537
26575
|
assistantStyle.top = `-3px`;
|
|
@@ -26557,7 +26595,6 @@ class Composer extends owl.Component {
|
|
|
26557
26595
|
F2: () => console.warn("Not implemented"),
|
|
26558
26596
|
F4: this.processF4Key,
|
|
26559
26597
|
Tab: (ev) => this.processTabKey(ev),
|
|
26560
|
-
" ": (ev) => this.processSpaceKey(ev),
|
|
26561
26598
|
};
|
|
26562
26599
|
keyCodeMapping = {
|
|
26563
26600
|
NumpadDecimal: this.processNumpadDecimal,
|
|
@@ -26565,12 +26602,12 @@ class Composer extends owl.Component {
|
|
|
26565
26602
|
setup() {
|
|
26566
26603
|
owl.onMounted(() => {
|
|
26567
26604
|
const el = this.composerRef.el;
|
|
26605
|
+
if (this.props.isDefaultFocus) {
|
|
26606
|
+
this.env.focusableElement.setFocusableElement(el);
|
|
26607
|
+
}
|
|
26568
26608
|
this.contentHelper.updateEl(el);
|
|
26569
26609
|
this.processTokenAtCursor();
|
|
26570
26610
|
});
|
|
26571
|
-
owl.onWillUnmount(() => {
|
|
26572
|
-
this.props.onComposerUnmounted?.();
|
|
26573
|
-
});
|
|
26574
26611
|
owl.useEffect(() => {
|
|
26575
26612
|
this.processContent();
|
|
26576
26613
|
});
|
|
@@ -26579,7 +26616,8 @@ class Composer extends owl.Component {
|
|
|
26579
26616
|
// Handlers
|
|
26580
26617
|
// ---------------------------------------------------------------------------
|
|
26581
26618
|
processArrowKeys(ev) {
|
|
26582
|
-
if (this.env.model.getters.isSelectingForComposer()
|
|
26619
|
+
if (this.env.model.getters.isSelectingForComposer() ||
|
|
26620
|
+
this.env.model.getters.getEditionMode() === "inactive") {
|
|
26583
26621
|
this.functionDescriptionState.showDescription = false;
|
|
26584
26622
|
// Prevent the default content editable behavior which moves the cursor
|
|
26585
26623
|
ev.preventDefault();
|
|
@@ -26622,26 +26660,20 @@ class Composer extends owl.Component {
|
|
|
26622
26660
|
processTabKey(ev) {
|
|
26623
26661
|
ev.preventDefault();
|
|
26624
26662
|
ev.stopPropagation();
|
|
26625
|
-
|
|
26626
|
-
|
|
26627
|
-
|
|
26628
|
-
|
|
26629
|
-
|
|
26630
|
-
|
|
26663
|
+
if (this.env.model.getters.getEditionMode() !== "inactive") {
|
|
26664
|
+
const state = this.autoCompleteState;
|
|
26665
|
+
if (state.showProvider && state.selectedIndex !== undefined) {
|
|
26666
|
+
const autoCompleteValue = this.autoCompleteState.values[state.selectedIndex]?.text;
|
|
26667
|
+
if (autoCompleteValue) {
|
|
26668
|
+
this.autoComplete(autoCompleteValue);
|
|
26669
|
+
return;
|
|
26670
|
+
}
|
|
26631
26671
|
}
|
|
26672
|
+
interactiveStopEdition(this.env);
|
|
26632
26673
|
}
|
|
26633
26674
|
const direction = ev.shiftKey ? "left" : "right";
|
|
26634
|
-
interactiveStopEdition(this.env);
|
|
26635
26675
|
this.env.model.selection.moveAnchorCell(direction, 1);
|
|
26636
26676
|
}
|
|
26637
|
-
processSpaceKey(ev) {
|
|
26638
|
-
if (ev.ctrlKey) {
|
|
26639
|
-
ev.preventDefault();
|
|
26640
|
-
ev.stopPropagation();
|
|
26641
|
-
this.showFunctionAutocomplete("");
|
|
26642
|
-
this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
|
|
26643
|
-
}
|
|
26644
|
-
}
|
|
26645
26677
|
processEnterKey(ev) {
|
|
26646
26678
|
ev.preventDefault();
|
|
26647
26679
|
ev.stopPropagation();
|
|
@@ -26694,6 +26726,9 @@ class Composer extends owl.Component {
|
|
|
26694
26726
|
this.compositionActive = false;
|
|
26695
26727
|
}
|
|
26696
26728
|
onKeydown(ev) {
|
|
26729
|
+
if (this.env.model.getters.getEditionMode() === "inactive") {
|
|
26730
|
+
return;
|
|
26731
|
+
}
|
|
26697
26732
|
let handler = this.keyMapping[ev.key] || this.keyCodeMapping[ev.code];
|
|
26698
26733
|
if (handler) {
|
|
26699
26734
|
handler.call(this, ev);
|
|
@@ -26702,14 +26737,33 @@ class Composer extends owl.Component {
|
|
|
26702
26737
|
ev.stopPropagation();
|
|
26703
26738
|
}
|
|
26704
26739
|
}
|
|
26740
|
+
onPaste(ev) {
|
|
26741
|
+
if (this.env.model.getters.getEditionMode() !== "inactive") {
|
|
26742
|
+
ev.stopPropagation();
|
|
26743
|
+
}
|
|
26744
|
+
}
|
|
26705
26745
|
/*
|
|
26706
26746
|
* Triggered automatically by the content-editable between the keydown and key up
|
|
26707
26747
|
* */
|
|
26708
26748
|
onInput(ev) {
|
|
26709
|
-
if (
|
|
26749
|
+
if (!this.shouldProcessInputEvents) {
|
|
26750
|
+
return;
|
|
26751
|
+
}
|
|
26752
|
+
if (ev.inputType === "insertFromPaste" &&
|
|
26753
|
+
this.env.model.getters.getEditionMode() === "inactive") {
|
|
26710
26754
|
return;
|
|
26711
26755
|
}
|
|
26712
|
-
|
|
26756
|
+
ev.stopPropagation();
|
|
26757
|
+
let content;
|
|
26758
|
+
if (this.env.model.getters.getEditionMode() === "inactive") {
|
|
26759
|
+
content = ev.data || "";
|
|
26760
|
+
}
|
|
26761
|
+
else {
|
|
26762
|
+
content = this.contentHelper.getText();
|
|
26763
|
+
}
|
|
26764
|
+
if (this.props.focus === "inactive") {
|
|
26765
|
+
return this.props.onComposerCellFocused?.(content);
|
|
26766
|
+
}
|
|
26713
26767
|
let selection = this.contentHelper.getCurrentSelection();
|
|
26714
26768
|
if (ev.inputType === "insertParagraph") {
|
|
26715
26769
|
const start = Math.min(selection.start, selection.end);
|
|
@@ -26791,9 +26845,8 @@ class Composer extends owl.Component {
|
|
|
26791
26845
|
}
|
|
26792
26846
|
const newSelection = this.contentHelper.getCurrentSelection();
|
|
26793
26847
|
this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
|
|
26794
|
-
|
|
26795
|
-
|
|
26796
|
-
}
|
|
26848
|
+
this.props.onComposerContentFocused();
|
|
26849
|
+
if (this.props.focus === "inactive") ;
|
|
26797
26850
|
this.env.model.dispatch("CHANGE_COMPOSER_CURSOR_SELECTION", newSelection);
|
|
26798
26851
|
this.processTokenAtCursor();
|
|
26799
26852
|
}
|
|
@@ -26960,7 +27013,7 @@ class Composer extends owl.Component {
|
|
|
26960
27013
|
const highlights = this.env.model.getters.getHighlights();
|
|
26961
27014
|
const refSheet = sheetName
|
|
26962
27015
|
? this.env.model.getters.getSheetIdByName(sheetName)
|
|
26963
|
-
: this.env.model.getters.getCurrentEditedCell()
|
|
27016
|
+
: this.env.model.getters.getCurrentEditedCell()?.sheetId;
|
|
26964
27017
|
const highlight = highlights.find((highlight) => {
|
|
26965
27018
|
if (highlight.sheetId !== refSheet)
|
|
26966
27019
|
return false;
|
|
@@ -27053,12 +27106,13 @@ class Composer extends owl.Component {
|
|
|
27053
27106
|
}
|
|
27054
27107
|
}
|
|
27055
27108
|
Composer.props = {
|
|
27056
|
-
focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
|
|
27057
|
-
onComposerContentFocused: Function,
|
|
27058
27109
|
inputStyle: { type: String, optional: true },
|
|
27059
27110
|
rect: { type: Object, optional: true },
|
|
27060
27111
|
delimitation: { type: Object, optional: true },
|
|
27061
|
-
|
|
27112
|
+
focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
|
|
27113
|
+
onComposerCellFocused: { type: Function, optional: true },
|
|
27114
|
+
onComposerContentFocused: Function,
|
|
27115
|
+
isDefaultFocus: { type: Boolean, optional: true },
|
|
27062
27116
|
};
|
|
27063
27117
|
|
|
27064
27118
|
const COMPOSER_BORDER_WIDTH = 3 * 0.4 * window.devicePixelRatio || 1;
|
|
@@ -27092,51 +27146,25 @@ css /* scss */ `
|
|
|
27092
27146
|
class GridComposer extends owl.Component {
|
|
27093
27147
|
static template = "o-spreadsheet-GridComposer";
|
|
27094
27148
|
static components = { Composer };
|
|
27095
|
-
|
|
27096
|
-
|
|
27097
|
-
rect;
|
|
27149
|
+
rect = this.defaultRect;
|
|
27150
|
+
isEditing = false;
|
|
27098
27151
|
isCellReferenceVisible;
|
|
27099
|
-
|
|
27152
|
+
get defaultRect() {
|
|
27153
|
+
return { x: 0, y: 0, width: 0, height: 0 };
|
|
27154
|
+
}
|
|
27100
27155
|
setup() {
|
|
27101
|
-
this.gridComposerRef = owl.useRef("gridComposer");
|
|
27102
|
-
this.composerState = owl.useState({
|
|
27103
|
-
rect: undefined,
|
|
27104
|
-
delimitation: undefined,
|
|
27105
|
-
});
|
|
27106
|
-
const { sheetId, col, row } = this.env.model.getters.getActivePosition();
|
|
27107
|
-
this.zone = this.env.model.getters.expandZone(sheetId, positionToZone({ col, row }));
|
|
27108
|
-
this.rect = this.env.model.getters.getVisibleRect(this.zone);
|
|
27109
|
-
this.isCellReferenceVisible = false;
|
|
27110
|
-
owl.onMounted(() => {
|
|
27111
|
-
const el = this.gridComposerRef.el;
|
|
27112
|
-
this.composerState.rect = {
|
|
27113
|
-
x: this.rect.x,
|
|
27114
|
-
y: this.rect.y,
|
|
27115
|
-
width: el.clientWidth,
|
|
27116
|
-
height: el.clientHeight,
|
|
27117
|
-
};
|
|
27118
|
-
this.composerState.delimitation = {
|
|
27119
|
-
width: this.props.gridDims.width,
|
|
27120
|
-
height: this.props.gridDims.height,
|
|
27121
|
-
};
|
|
27122
|
-
});
|
|
27123
27156
|
owl.onWillUpdateProps(() => {
|
|
27124
|
-
|
|
27125
|
-
|
|
27126
|
-
}
|
|
27127
|
-
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
27128
|
-
const zone = this.env.model.getters.getSelectedZone();
|
|
27129
|
-
const rect = this.env.model.getters.getVisibleRect(zone);
|
|
27130
|
-
if (!deepEquals(rect, this.rect) ||
|
|
27131
|
-
sheetId !== this.env.model.getters.getCurrentEditedCell().sheetId) {
|
|
27132
|
-
this.isCellReferenceVisible = true;
|
|
27133
|
-
}
|
|
27157
|
+
this.updateComponentPosition();
|
|
27158
|
+
this.updateCellReferenceVisibility();
|
|
27134
27159
|
});
|
|
27135
27160
|
}
|
|
27136
27161
|
get shouldDisplayCellReference() {
|
|
27137
27162
|
return this.isCellReferenceVisible;
|
|
27138
27163
|
}
|
|
27139
27164
|
get cellReference() {
|
|
27165
|
+
if (!this.env.model.getters.getCurrentEditedCell()) {
|
|
27166
|
+
return "";
|
|
27167
|
+
}
|
|
27140
27168
|
const { col, row, sheetId } = this.env.model.getters.getCurrentEditedCell();
|
|
27141
27169
|
const prefixSheet = sheetId !== this.env.model.getters.getActiveSheetId();
|
|
27142
27170
|
return `${prefixSheet ? getCanonicalSheetName(this.env.model.getters.getSheetName(sheetId)) + "!" : ""}${toXC(col, row)}`;
|
|
@@ -27148,7 +27176,27 @@ class GridComposer extends owl.Component {
|
|
|
27148
27176
|
top: `${top - GRID_CELL_REFERENCE_TOP_OFFSET}px`,
|
|
27149
27177
|
});
|
|
27150
27178
|
}
|
|
27179
|
+
get composerProps() {
|
|
27180
|
+
const { width, height } = this.env.model.getters.getSheetViewDimensionWithHeaders();
|
|
27181
|
+
return {
|
|
27182
|
+
rect: { ...this.rect },
|
|
27183
|
+
delimitation: {
|
|
27184
|
+
width,
|
|
27185
|
+
height,
|
|
27186
|
+
},
|
|
27187
|
+
focus: this.props.focus,
|
|
27188
|
+
isDefaultFocus: true,
|
|
27189
|
+
onComposerContentFocused: this.props.onComposerContentFocused,
|
|
27190
|
+
onComposerCellFocused: this.props.onComposerCellFocused,
|
|
27191
|
+
};
|
|
27192
|
+
}
|
|
27151
27193
|
get containerStyle() {
|
|
27194
|
+
if (this.env.model.getters.getEditionMode() === "inactive" || !this.rect) {
|
|
27195
|
+
return `
|
|
27196
|
+
position: absolute;
|
|
27197
|
+
z-index: -1000;
|
|
27198
|
+
`;
|
|
27199
|
+
}
|
|
27152
27200
|
const isFormula = this.env.model.getters.getCurrentContent().startsWith("=");
|
|
27153
27201
|
const cell = this.env.model.getters.getActiveCell();
|
|
27154
27202
|
const position = this.env.model.getters.getActivePosition();
|
|
@@ -27168,6 +27216,8 @@ class GridComposer extends owl.Component {
|
|
|
27168
27216
|
if (!isFormula) {
|
|
27169
27217
|
textAlign = style.align || cell.defaultAlign;
|
|
27170
27218
|
}
|
|
27219
|
+
const maxHeight = this.props.gridDims.height - this.rect.y;
|
|
27220
|
+
const maxWidth = this.props.gridDims.width - this.rect.x;
|
|
27171
27221
|
/**
|
|
27172
27222
|
* min-size is on the container, not the composer element, because we want to have the same size as the cell by default,
|
|
27173
27223
|
* including all the paddings/margins of the composer
|
|
@@ -27179,6 +27229,8 @@ class GridComposer extends owl.Component {
|
|
|
27179
27229
|
top: `${top}px`,
|
|
27180
27230
|
"min-width": `${width + 1}px`,
|
|
27181
27231
|
"min-height": `${height + 1}px`,
|
|
27232
|
+
"max-width": `${maxWidth}px`,
|
|
27233
|
+
"max-height": `${maxHeight}px`,
|
|
27182
27234
|
background,
|
|
27183
27235
|
color,
|
|
27184
27236
|
"font-size": `${fontSizeInPixels(fontSize)}px`,
|
|
@@ -27188,20 +27240,38 @@ class GridComposer extends owl.Component {
|
|
|
27188
27240
|
"text-align": textAlign,
|
|
27189
27241
|
});
|
|
27190
27242
|
}
|
|
27191
|
-
|
|
27192
|
-
const
|
|
27193
|
-
|
|
27194
|
-
|
|
27195
|
-
|
|
27196
|
-
|
|
27197
|
-
|
|
27243
|
+
updateComponentPosition() {
|
|
27244
|
+
const isEditing = this.env.model.getters.getEditionMode() !== "inactive";
|
|
27245
|
+
if (this.isEditing !== isEditing) {
|
|
27246
|
+
this.isEditing = isEditing;
|
|
27247
|
+
if (!isEditing) {
|
|
27248
|
+
this.rect = this.defaultRect;
|
|
27249
|
+
this.env.focusableElement.focus();
|
|
27250
|
+
return;
|
|
27251
|
+
}
|
|
27252
|
+
const position = this.env.model.getters.getActivePosition();
|
|
27253
|
+
const zone = this.env.model.getters.expandZone(position.sheetId, positionToZone(position));
|
|
27254
|
+
this.rect = this.env.model.getters.getVisibleRect(zone);
|
|
27255
|
+
}
|
|
27256
|
+
}
|
|
27257
|
+
updateCellReferenceVisibility() {
|
|
27258
|
+
if (this.isCellReferenceVisible || this.env.model.getters.getEditionMode() === "inactive") {
|
|
27259
|
+
return;
|
|
27260
|
+
}
|
|
27261
|
+
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
27262
|
+
const zone = this.env.model.getters.getSelectedZone();
|
|
27263
|
+
const rect = this.env.model.getters.getVisibleRect(zone);
|
|
27264
|
+
if (!deepEquals(rect, this.rect) ||
|
|
27265
|
+
sheetId !== this.env.model.getters.getCurrentEditedCell().sheetId) {
|
|
27266
|
+
this.isCellReferenceVisible = true;
|
|
27267
|
+
}
|
|
27198
27268
|
}
|
|
27199
27269
|
}
|
|
27200
27270
|
GridComposer.props = {
|
|
27201
27271
|
focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
|
|
27202
|
-
onComposerUnmounted: Function,
|
|
27203
27272
|
onComposerContentFocused: Function,
|
|
27204
27273
|
gridDims: Object,
|
|
27274
|
+
onComposerCellFocused: Function,
|
|
27205
27275
|
};
|
|
27206
27276
|
|
|
27207
27277
|
const CSS$1 = css /* scss */ `
|
|
@@ -28292,7 +28362,6 @@ class GridOverlay extends owl.Component {
|
|
|
28292
28362
|
this.props.onCellDoubleClicked(col, row);
|
|
28293
28363
|
}
|
|
28294
28364
|
onContextMenu(ev) {
|
|
28295
|
-
ev.preventDefault();
|
|
28296
28365
|
const [col, row] = this.getCartesianCoordinates(ev);
|
|
28297
28366
|
this.props.onCellRightClicked(col, row, { x: ev.clientX, y: ev.clientY });
|
|
28298
28367
|
}
|
|
@@ -29353,6 +29422,7 @@ const registries$1 = {
|
|
|
29353
29422
|
GROUP_HEADERS: groupHeadersMenuRegistry,
|
|
29354
29423
|
UNGROUP_HEADERS: unGroupHeadersMenuRegistry,
|
|
29355
29424
|
};
|
|
29425
|
+
const MODIFIER_KEYS = ["Shift", "Control", "Alt", "Meta"];
|
|
29356
29426
|
// -----------------------------------------------------------------------------
|
|
29357
29427
|
// JS
|
|
29358
29428
|
// -----------------------------------------------------------------------------
|
|
@@ -29376,7 +29446,6 @@ class Grid extends owl.Component {
|
|
|
29376
29446
|
HEADER_WIDTH = HEADER_WIDTH;
|
|
29377
29447
|
menuState;
|
|
29378
29448
|
gridRef;
|
|
29379
|
-
hiddenInput;
|
|
29380
29449
|
onMouseWheel;
|
|
29381
29450
|
canvasPosition;
|
|
29382
29451
|
hoveredCell;
|
|
@@ -29387,17 +29456,16 @@ class Grid extends owl.Component {
|
|
|
29387
29456
|
menuItems: [],
|
|
29388
29457
|
});
|
|
29389
29458
|
this.gridRef = owl.useRef("grid");
|
|
29390
|
-
this.hiddenInput = owl.useRef("hiddenInput");
|
|
29391
29459
|
this.canvasPosition = useAbsoluteBoundingRect(this.gridRef);
|
|
29392
29460
|
this.hoveredCell = owl.useState({ col: undefined, row: undefined });
|
|
29393
29461
|
owl.useChildSubEnv({ getPopoverContainerRect: () => this.getGridRect() });
|
|
29394
29462
|
owl.useExternalListener(document.body, "cut", this.copy.bind(this, true));
|
|
29395
29463
|
owl.useExternalListener(document.body, "copy", this.copy.bind(this, false));
|
|
29396
29464
|
owl.useExternalListener(document.body, "paste", this.paste);
|
|
29397
|
-
owl.onMounted(() => this.
|
|
29398
|
-
this.props.exposeFocus(() => this.
|
|
29465
|
+
owl.onMounted(() => this.focusDefaultElement());
|
|
29466
|
+
this.props.exposeFocus(() => this.focusDefaultElement());
|
|
29399
29467
|
useGridDrawing("canvas", this.env.model, () => this.env.model.getters.getSheetViewDimensionWithHeaders());
|
|
29400
|
-
owl.useEffect(() => this.
|
|
29468
|
+
owl.useEffect(() => this.focusDefaultElement(), () => [this.env.model.getters.getActiveSheetId()]);
|
|
29401
29469
|
this.onMouseWheel = useWheelHandler((deltaX, deltaY) => {
|
|
29402
29470
|
this.moveCanvas(deltaX, deltaY);
|
|
29403
29471
|
this.hoveredCell.col = undefined;
|
|
@@ -29420,7 +29488,7 @@ class Grid extends owl.Component {
|
|
|
29420
29488
|
if (this.env.model.getters.hasOpenedPopover()) {
|
|
29421
29489
|
this.closeOpenedPopover();
|
|
29422
29490
|
}
|
|
29423
|
-
this.
|
|
29491
|
+
this.focusDefaultElement();
|
|
29424
29492
|
}
|
|
29425
29493
|
// this map will handle most of the actions that should happen on key down. The arrow keys are managed in the key
|
|
29426
29494
|
// down itself
|
|
@@ -29599,10 +29667,10 @@ class Grid extends owl.Component {
|
|
|
29599
29667
|
"ALT+SHIFT+ARROWUP": () => this.processHeaderGroupingKey("up"),
|
|
29600
29668
|
"ALT+SHIFT+ARROWDOWN": () => this.processHeaderGroupingKey("down"),
|
|
29601
29669
|
};
|
|
29602
|
-
|
|
29670
|
+
focusDefaultElement() {
|
|
29603
29671
|
if (!this.env.model.getters.getSelectedFigureId() &&
|
|
29604
29672
|
this.env.model.getters.getEditionMode() === "inactive") {
|
|
29605
|
-
this.
|
|
29673
|
+
this.env.focusableElement.focus();
|
|
29606
29674
|
}
|
|
29607
29675
|
}
|
|
29608
29676
|
get gridEl() {
|
|
@@ -29725,16 +29793,15 @@ class Grid extends owl.Component {
|
|
|
29725
29793
|
}
|
|
29726
29794
|
}
|
|
29727
29795
|
onKeydown(ev) {
|
|
29728
|
-
const eventKey = ev.key.toUpperCase();
|
|
29729
29796
|
let keyDownString = "";
|
|
29730
|
-
if (
|
|
29731
|
-
|
|
29732
|
-
|
|
29733
|
-
|
|
29734
|
-
|
|
29735
|
-
|
|
29736
|
-
|
|
29737
|
-
|
|
29797
|
+
if (!MODIFIER_KEYS.includes(ev.key)) {
|
|
29798
|
+
if (isCtrlKey(ev))
|
|
29799
|
+
keyDownString += "CTRL+";
|
|
29800
|
+
if (ev.altKey)
|
|
29801
|
+
keyDownString += "ALT+";
|
|
29802
|
+
if (ev.shiftKey)
|
|
29803
|
+
keyDownString += "SHIFT+";
|
|
29804
|
+
}
|
|
29738
29805
|
keyDownString += ev.key.toUpperCase();
|
|
29739
29806
|
let handler = this.keyDownMapping[keyDownString];
|
|
29740
29807
|
if (handler) {
|
|
@@ -29748,19 +29815,6 @@ class Grid extends owl.Component {
|
|
|
29748
29815
|
return;
|
|
29749
29816
|
}
|
|
29750
29817
|
}
|
|
29751
|
-
onInput(ev) {
|
|
29752
|
-
// the user meant to paste in the sheet, not open the composer with the pasted content
|
|
29753
|
-
if (!ev.isComposing && ev.inputType === "insertFromPaste") {
|
|
29754
|
-
return;
|
|
29755
|
-
}
|
|
29756
|
-
if (ev.data) {
|
|
29757
|
-
// if the user types a character on the grid, it means he wants to start composing the selected cell with that
|
|
29758
|
-
// character
|
|
29759
|
-
ev.preventDefault();
|
|
29760
|
-
ev.stopPropagation();
|
|
29761
|
-
this.props.onGridComposerCellFocused(ev.data);
|
|
29762
|
-
}
|
|
29763
|
-
}
|
|
29764
29818
|
// ---------------------------------------------------------------------------
|
|
29765
29819
|
// Context Menu
|
|
29766
29820
|
// ---------------------------------------------------------------------------
|
|
@@ -29875,7 +29929,7 @@ class Grid extends owl.Component {
|
|
|
29875
29929
|
}
|
|
29876
29930
|
closeMenu() {
|
|
29877
29931
|
this.menuState.isOpen = false;
|
|
29878
|
-
this.
|
|
29932
|
+
this.focusDefaultElement();
|
|
29879
29933
|
}
|
|
29880
29934
|
processHeaderGroupingKey(direction) {
|
|
29881
29935
|
if (this.env.model.getters.getSelectedZones().length !== 1) {
|
|
@@ -33770,6 +33824,31 @@ const MIGRATIONS = [
|
|
|
33770
33824
|
return data;
|
|
33771
33825
|
},
|
|
33772
33826
|
},
|
|
33827
|
+
{
|
|
33828
|
+
description: "Fix datafilter duplication",
|
|
33829
|
+
from: 12,
|
|
33830
|
+
to: 12.5,
|
|
33831
|
+
applyMigration(data) {
|
|
33832
|
+
for (let sheet of data.sheets || []) {
|
|
33833
|
+
let knownDataFilterZones = [];
|
|
33834
|
+
for (let filterTable of sheet.filterTables || []) {
|
|
33835
|
+
const zone = toZone(filterTable.range);
|
|
33836
|
+
// See commit message for the details
|
|
33837
|
+
const intersectZoneIndex = knownDataFilterZones.findIndex((knownZone) => overlap(knownZone, zone));
|
|
33838
|
+
if (intersectZoneIndex !== -1) {
|
|
33839
|
+
knownDataFilterZones[intersectZoneIndex] = zone;
|
|
33840
|
+
}
|
|
33841
|
+
else {
|
|
33842
|
+
knownDataFilterZones.push(zone);
|
|
33843
|
+
}
|
|
33844
|
+
}
|
|
33845
|
+
sheet.filterTables = knownDataFilterZones.map((zone) => ({
|
|
33846
|
+
range: zoneToXc(zone),
|
|
33847
|
+
}));
|
|
33848
|
+
}
|
|
33849
|
+
return data;
|
|
33850
|
+
},
|
|
33851
|
+
},
|
|
33773
33852
|
{
|
|
33774
33853
|
description: "Change Border description structure",
|
|
33775
33854
|
from: 12,
|
|
@@ -34609,22 +34688,7 @@ class BordersPlugin extends CorePlugin {
|
|
|
34609
34688
|
}
|
|
34610
34689
|
}
|
|
34611
34690
|
export(data) {
|
|
34612
|
-
// Borders
|
|
34613
|
-
let borderId = 0;
|
|
34614
34691
|
const borders = {};
|
|
34615
|
-
/**
|
|
34616
|
-
* Get the id of the given border. If the border does not exist, it creates
|
|
34617
|
-
* one.
|
|
34618
|
-
*/
|
|
34619
|
-
function getBorderId(border) {
|
|
34620
|
-
for (let [key, value] of Object.entries(borders)) {
|
|
34621
|
-
if (deepEquals(value, border)) {
|
|
34622
|
-
return parseInt(key, 10);
|
|
34623
|
-
}
|
|
34624
|
-
}
|
|
34625
|
-
borders[++borderId] = border;
|
|
34626
|
-
return borderId;
|
|
34627
|
-
}
|
|
34628
34692
|
for (let sheet of data.sheets) {
|
|
34629
34693
|
for (let col = 0; col < sheet.colNumber; col++) {
|
|
34630
34694
|
for (let row = 0; row < sheet.rowNumber; row++) {
|
|
@@ -34632,7 +34696,7 @@ class BordersPlugin extends CorePlugin {
|
|
|
34632
34696
|
if (border) {
|
|
34633
34697
|
const xc = toXC(col, row);
|
|
34634
34698
|
const cell = sheet.cells[xc];
|
|
34635
|
-
const borderId =
|
|
34699
|
+
const borderId = getItemId(border, borders);
|
|
34636
34700
|
if (cell) {
|
|
34637
34701
|
cell.border = borderId;
|
|
34638
34702
|
}
|
|
@@ -35437,9 +35501,9 @@ class CellPlugin extends CorePlugin {
|
|
|
35437
35501
|
allowDispatch(cmd) {
|
|
35438
35502
|
switch (cmd.type) {
|
|
35439
35503
|
case "UPDATE_CELL":
|
|
35440
|
-
return this.
|
|
35504
|
+
return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessUpdateCell);
|
|
35441
35505
|
case "CLEAR_CELL":
|
|
35442
|
-
return this.checkValidations(cmd, this.
|
|
35506
|
+
return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessClearCell);
|
|
35443
35507
|
default:
|
|
35444
35508
|
return "Success" /* CommandResult.Success */;
|
|
35445
35509
|
}
|
|
@@ -35589,8 +35653,8 @@ class CellPlugin extends CorePlugin {
|
|
|
35589
35653
|
}
|
|
35590
35654
|
removeDefaultStyleValues(style) {
|
|
35591
35655
|
const cleanedStyle = { ...style };
|
|
35592
|
-
for (const
|
|
35593
|
-
if (cleanedStyle[property] ===
|
|
35656
|
+
for (const property in DEFAULT_STYLE) {
|
|
35657
|
+
if (cleanedStyle[property] === DEFAULT_STYLE[property]) {
|
|
35594
35658
|
delete cleanedStyle[property];
|
|
35595
35659
|
}
|
|
35596
35660
|
}
|
|
@@ -35615,13 +35679,13 @@ class CellPlugin extends CorePlugin {
|
|
|
35615
35679
|
/*
|
|
35616
35680
|
* Reconstructs the original formula string based on a normalized form and its dependencies
|
|
35617
35681
|
*/
|
|
35618
|
-
getFormulaCellContent(sheetId, compiledFormula, dependencies) {
|
|
35682
|
+
getFormulaCellContent(sheetId, compiledFormula, dependencies, useFixedReference = false) {
|
|
35619
35683
|
const ranges = dependencies || compiledFormula.dependencies;
|
|
35620
35684
|
let rangeIndex = 0;
|
|
35621
35685
|
return concat(compiledFormula.tokens.map((token) => {
|
|
35622
35686
|
if (token.type === "REFERENCE") {
|
|
35623
35687
|
const range = ranges[rangeIndex++];
|
|
35624
|
-
return this.getters.getRangeString(range, sheetId);
|
|
35688
|
+
return this.getters.getRangeString(range, sheetId, { useFixedReference });
|
|
35625
35689
|
}
|
|
35626
35690
|
return token.value;
|
|
35627
35691
|
}));
|
|
@@ -35747,10 +35811,7 @@ class CellPlugin extends CorePlugin {
|
|
|
35747
35811
|
else {
|
|
35748
35812
|
style = before ? before.style : undefined;
|
|
35749
35813
|
}
|
|
35750
|
-
const
|
|
35751
|
-
let format = ("format" in after ? after.format : before && before.format) ||
|
|
35752
|
-
detectDateFormat(afterContent, locale) ||
|
|
35753
|
-
detectNumberFormat(afterContent);
|
|
35814
|
+
const format = "format" in after ? after.format : before && before.format;
|
|
35754
35815
|
/* Read the following IF as:
|
|
35755
35816
|
* we need to remove the cell if it is completely empty, but we can know if it completely empty if:
|
|
35756
35817
|
* - the command says the new content is empty and has no border/format/style
|
|
@@ -35791,12 +35852,11 @@ class CellPlugin extends CorePlugin {
|
|
|
35791
35852
|
}
|
|
35792
35853
|
createLiteralCell(id, content, format, style) {
|
|
35793
35854
|
const locale = this.getters.getLocale();
|
|
35794
|
-
content = parseLiteral(content, locale).toString();
|
|
35795
35855
|
return {
|
|
35796
35856
|
id,
|
|
35797
|
-
content,
|
|
35857
|
+
content: parseLiteral(content, locale).toString(),
|
|
35798
35858
|
style,
|
|
35799
|
-
format,
|
|
35859
|
+
format: format || detectDateFormat(content, locale) || detectNumberFormat(content),
|
|
35800
35860
|
isFormula: false,
|
|
35801
35861
|
};
|
|
35802
35862
|
}
|
|
@@ -35822,8 +35882,11 @@ class CellPlugin extends CorePlugin {
|
|
|
35822
35882
|
* being a computed property to rebuild the dependencies XC.
|
|
35823
35883
|
*/
|
|
35824
35884
|
createFormulaCellWithDependencies(id, compiledFormula, format, style, sheetId) {
|
|
35825
|
-
const dependencies =
|
|
35826
|
-
|
|
35885
|
+
const dependencies = [];
|
|
35886
|
+
for (const xc of compiledFormula.dependencies) {
|
|
35887
|
+
dependencies.push(this.getters.getRangeFromSheetXC(sheetId, xc));
|
|
35888
|
+
}
|
|
35889
|
+
return new FormulaCellWithDependencies(id, compiledFormula, format, style, dependencies, sheetId, this.getters.getRangeString);
|
|
35827
35890
|
}
|
|
35828
35891
|
createErrorFormula(id, content, format, style, error) {
|
|
35829
35892
|
return {
|
|
@@ -35858,6 +35921,18 @@ class CellPlugin extends CorePlugin {
|
|
|
35858
35921
|
}
|
|
35859
35922
|
return "Success" /* CommandResult.Success */;
|
|
35860
35923
|
}
|
|
35924
|
+
checkUselessUpdateCell(cmd) {
|
|
35925
|
+
const cell = this.getters.getCell(cmd);
|
|
35926
|
+
const hasContent = "content" in cmd || "formula" in cmd;
|
|
35927
|
+
const hasStyle = "style" in cmd;
|
|
35928
|
+
const hasFormat = "format" in cmd;
|
|
35929
|
+
if ((!hasContent || cell?.content === cmd.content) &&
|
|
35930
|
+
(!hasStyle || deepEquals(cell?.style, cmd.style)) &&
|
|
35931
|
+
(!hasFormat || cell?.format === cmd.format)) {
|
|
35932
|
+
return "NoChanges" /* CommandResult.NoChanges */;
|
|
35933
|
+
}
|
|
35934
|
+
return "Success" /* CommandResult.Success */;
|
|
35935
|
+
}
|
|
35861
35936
|
}
|
|
35862
35937
|
class FormulaCellWithDependencies {
|
|
35863
35938
|
id;
|
|
@@ -35877,7 +35952,7 @@ class FormulaCellWithDependencies {
|
|
|
35877
35952
|
const tokens = compiledFormula.tokens.map((token) => {
|
|
35878
35953
|
if (token.type === "REFERENCE") {
|
|
35879
35954
|
const index = rangeIndex++;
|
|
35880
|
-
return new RangeReferenceToken(
|
|
35955
|
+
return new RangeReferenceToken(dependencies, index, this.sheetId, this.getRangeString);
|
|
35881
35956
|
}
|
|
35882
35957
|
return token;
|
|
35883
35958
|
});
|
|
@@ -35890,15 +35965,34 @@ class FormulaCellWithDependencies {
|
|
|
35890
35965
|
get content() {
|
|
35891
35966
|
return concat(this.compiledFormula.tokens.map((token) => token.value));
|
|
35892
35967
|
}
|
|
35968
|
+
get contentWithFixedReferences() {
|
|
35969
|
+
let rangeIndex = 0;
|
|
35970
|
+
return concat(this.compiledFormula.tokens.map((token) => {
|
|
35971
|
+
if (token.type === "REFERENCE") {
|
|
35972
|
+
const index = rangeIndex++;
|
|
35973
|
+
return this.getRangeString(this.compiledFormula.dependencies[index], this.sheetId, {
|
|
35974
|
+
useFixedReference: true,
|
|
35975
|
+
});
|
|
35976
|
+
}
|
|
35977
|
+
return token.value;
|
|
35978
|
+
}));
|
|
35979
|
+
}
|
|
35893
35980
|
}
|
|
35894
35981
|
class RangeReferenceToken {
|
|
35895
|
-
|
|
35982
|
+
ranges;
|
|
35983
|
+
rangeIndex;
|
|
35984
|
+
sheetId;
|
|
35985
|
+
getRangeString;
|
|
35896
35986
|
type = "REFERENCE";
|
|
35897
|
-
constructor(
|
|
35898
|
-
this.
|
|
35987
|
+
constructor(ranges, rangeIndex, sheetId, getRangeString) {
|
|
35988
|
+
this.ranges = ranges;
|
|
35989
|
+
this.rangeIndex = rangeIndex;
|
|
35990
|
+
this.sheetId = sheetId;
|
|
35991
|
+
this.getRangeString = getRangeString;
|
|
35899
35992
|
}
|
|
35900
35993
|
get value() {
|
|
35901
|
-
|
|
35994
|
+
const range = this.ranges[this.rangeIndex];
|
|
35995
|
+
return this.getRangeString(range, this.sheetId);
|
|
35902
35996
|
}
|
|
35903
35997
|
}
|
|
35904
35998
|
|
|
@@ -36194,7 +36288,13 @@ class ConditionalFormatPlugin extends CorePlugin {
|
|
|
36194
36288
|
}
|
|
36195
36289
|
}
|
|
36196
36290
|
exportForExcel(data) {
|
|
36197
|
-
|
|
36291
|
+
if (data.sheets) {
|
|
36292
|
+
for (let sheet of data.sheets) {
|
|
36293
|
+
if (this.cfRules[sheet.id]) {
|
|
36294
|
+
sheet.conditionalFormats = this.cfRules[sheet.id].map((rule) => this.mapToConditionalFormat(sheet.id, rule, { useFixedReference: true }));
|
|
36295
|
+
}
|
|
36296
|
+
}
|
|
36297
|
+
}
|
|
36198
36298
|
}
|
|
36199
36299
|
// ---------------------------------------------------------------------------
|
|
36200
36300
|
// Getters
|
|
@@ -36259,11 +36359,11 @@ class ConditionalFormatPlugin extends CorePlugin {
|
|
|
36259
36359
|
// ---------------------------------------------------------------------------
|
|
36260
36360
|
// Private
|
|
36261
36361
|
// ---------------------------------------------------------------------------
|
|
36262
|
-
mapToConditionalFormat(sheetId, cf) {
|
|
36362
|
+
mapToConditionalFormat(sheetId, cf, { useFixedReference } = { useFixedReference: false }) {
|
|
36263
36363
|
return {
|
|
36264
36364
|
...cf,
|
|
36265
36365
|
ranges: cf.ranges.map((range) => {
|
|
36266
|
-
return this.getters.getRangeString(range, sheetId);
|
|
36366
|
+
return this.getters.getRangeString(range, sheetId, { useFixedReference });
|
|
36267
36367
|
}),
|
|
36268
36368
|
};
|
|
36269
36369
|
}
|
|
@@ -38331,8 +38431,10 @@ class RangeAdapter {
|
|
|
38331
38431
|
*
|
|
38332
38432
|
* @param range the range (received from getRangeFromXC or getRangeFromZone)
|
|
38333
38433
|
* @param forSheetId the id of the sheet where the range string is supposed to be used.
|
|
38434
|
+
* @param options
|
|
38435
|
+
* @param options.useFixedReference if true, the range will be returned with fixed row and column
|
|
38334
38436
|
*/
|
|
38335
|
-
getRangeString(range, forSheetId) {
|
|
38437
|
+
getRangeString(range, forSheetId, options = { useFixedReference: false }) {
|
|
38336
38438
|
if (!range) {
|
|
38337
38439
|
return INCORRECT_RANGE_STRING;
|
|
38338
38440
|
}
|
|
@@ -38359,7 +38461,7 @@ class RangeAdapter {
|
|
|
38359
38461
|
if (prefixSheet && !sheetName) {
|
|
38360
38462
|
return INCORRECT_RANGE_STRING;
|
|
38361
38463
|
}
|
|
38362
|
-
let rangeString = this.getRangePartString(rangeImpl, 0);
|
|
38464
|
+
let rangeString = this.getRangePartString(rangeImpl, 0, options);
|
|
38363
38465
|
if (rangeImpl.parts && rangeImpl.parts.length === 2) {
|
|
38364
38466
|
// this if converts A2:A2 into A2 except if any part of the original range had fixed row or column (with $)
|
|
38365
38467
|
if (rangeImpl.zone.top !== rangeImpl.zone.bottom ||
|
|
@@ -38369,7 +38471,7 @@ class RangeAdapter {
|
|
|
38369
38471
|
rangeImpl.parts[1].rowFixed ||
|
|
38370
38472
|
rangeImpl.parts[1].colFixed) {
|
|
38371
38473
|
rangeString += ":";
|
|
38372
|
-
rangeString += this.getRangePartString(rangeImpl, 1);
|
|
38474
|
+
rangeString += this.getRangePartString(rangeImpl, 1, options);
|
|
38373
38475
|
}
|
|
38374
38476
|
}
|
|
38375
38477
|
return `${prefixSheet ? sheetName + "!" : ""}${rangeString}`;
|
|
@@ -38410,13 +38512,13 @@ class RangeAdapter {
|
|
|
38410
38512
|
/**
|
|
38411
38513
|
* Get a Xc string that represent a part of a range
|
|
38412
38514
|
*/
|
|
38413
|
-
getRangePartString(range, part) {
|
|
38515
|
+
getRangePartString(range, part, options = { useFixedReference: false }) {
|
|
38414
38516
|
const colFixed = range.parts && range.parts[part]?.colFixed ? "$" : "";
|
|
38415
38517
|
const col = part === 0 ? numberToLetters(range.zone.left) : numberToLetters(range.zone.right);
|
|
38416
38518
|
const rowFixed = range.parts && range.parts[part]?.rowFixed ? "$" : "";
|
|
38417
38519
|
const row = part === 0 ? String(range.zone.top + 1) : String(range.zone.bottom + 1);
|
|
38418
38520
|
let str = "";
|
|
38419
|
-
if (range.isFullCol) {
|
|
38521
|
+
if (range.isFullCol && !options.useFixedReference) {
|
|
38420
38522
|
if (part === 0 && range.unboundedZone.hasHeader) {
|
|
38421
38523
|
str = colFixed + col + rowFixed + row;
|
|
38422
38524
|
}
|
|
@@ -38424,7 +38526,7 @@ class RangeAdapter {
|
|
|
38424
38526
|
str = colFixed + col;
|
|
38425
38527
|
}
|
|
38426
38528
|
}
|
|
38427
|
-
else if (range.isFullRow) {
|
|
38529
|
+
else if (range.isFullRow && !options.useFixedReference) {
|
|
38428
38530
|
if (part === 0 && range.unboundedZone.hasHeader) {
|
|
38429
38531
|
str = colFixed + col + rowFixed + row;
|
|
38430
38532
|
}
|
|
@@ -40626,7 +40728,15 @@ class SpreadsheetRTree {
|
|
|
40626
40728
|
if (!this.rTrees[sheetId]) {
|
|
40627
40729
|
return;
|
|
40628
40730
|
}
|
|
40629
|
-
this.rTrees[sheetId].remove(item,
|
|
40731
|
+
this.rTrees[sheetId].remove(item, this.rtreeItemComparer);
|
|
40732
|
+
}
|
|
40733
|
+
rtreeItemComparer(left, right) {
|
|
40734
|
+
return (left.data == right.data &&
|
|
40735
|
+
left.boundingBox.sheetId === right.boundingBox.sheetId &&
|
|
40736
|
+
left.boundingBox?.zone.left === right.boundingBox.zone.left &&
|
|
40737
|
+
left.boundingBox?.zone.top === right.boundingBox.zone.top &&
|
|
40738
|
+
left.boundingBox?.zone.right === right.boundingBox.zone.right &&
|
|
40739
|
+
left.boundingBox?.zone.bottom === right.boundingBox.zone.bottom);
|
|
40630
40740
|
}
|
|
40631
40741
|
}
|
|
40632
40742
|
/**
|
|
@@ -40704,7 +40814,7 @@ class FormulaDependencyGraph {
|
|
|
40704
40814
|
const queue = Array.from(ranges).reverse();
|
|
40705
40815
|
while (queue.length > 0) {
|
|
40706
40816
|
const range = queue.pop();
|
|
40707
|
-
visited.
|
|
40817
|
+
visited.addMany(this.encoder.encodeBoundingBox(range));
|
|
40708
40818
|
const impactedPositionIds = this.rTree.search(range).map((dep) => dep.data);
|
|
40709
40819
|
for (const positionId of impactedPositionIds) {
|
|
40710
40820
|
if (!visited.has(positionId)) {
|
|
@@ -40712,7 +40822,7 @@ class FormulaDependencyGraph {
|
|
|
40712
40822
|
}
|
|
40713
40823
|
}
|
|
40714
40824
|
}
|
|
40715
|
-
visited.
|
|
40825
|
+
visited.deleteMany(ranges.flatMap((r) => this.encoder.encodeBoundingBox(r)));
|
|
40716
40826
|
return visited;
|
|
40717
40827
|
}
|
|
40718
40828
|
}
|
|
@@ -40850,9 +40960,9 @@ class Evaluator {
|
|
|
40850
40960
|
const cells = positions.map((p) => this.encoder.encode(p));
|
|
40851
40961
|
const cellsToCompute = new JetSet(cells);
|
|
40852
40962
|
const arrayFormulasPositionIds = this.getArrayFormulasImpactedByChangesOf(cells);
|
|
40853
|
-
cellsToCompute.
|
|
40854
|
-
cellsToCompute.
|
|
40855
|
-
cellsToCompute.
|
|
40963
|
+
cellsToCompute.addMany(this.getCellsDependingOn(cells));
|
|
40964
|
+
cellsToCompute.addMany(arrayFormulasPositionIds);
|
|
40965
|
+
cellsToCompute.addMany(this.getCellsDependingOn(arrayFormulasPositionIds));
|
|
40856
40966
|
this.evaluate(cellsToCompute);
|
|
40857
40967
|
}
|
|
40858
40968
|
getArrayFormulasImpactedByChangesOf(positionIds) {
|
|
@@ -40866,7 +40976,7 @@ class Evaluator {
|
|
|
40866
40976
|
}
|
|
40867
40977
|
if (!content) {
|
|
40868
40978
|
// The previous content could have blocked some array formulas
|
|
40869
|
-
impactedPositionIds.
|
|
40979
|
+
impactedPositionIds.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(positionId));
|
|
40870
40980
|
}
|
|
40871
40981
|
}
|
|
40872
40982
|
return impactedPositionIds;
|
|
@@ -40915,7 +41025,7 @@ class Evaluator {
|
|
|
40915
41025
|
}
|
|
40916
41026
|
const arrayFormulas = this.spreadingRelations.getFormulaPositionsSpreadingOn(positionId);
|
|
40917
41027
|
const cells = new JetSet(arrayFormulas);
|
|
40918
|
-
cells.
|
|
41028
|
+
cells.addMany(this.getCellsDependingOn(arrayFormulas));
|
|
40919
41029
|
return cells;
|
|
40920
41030
|
}
|
|
40921
41031
|
nextPositionsToUpdate = new JetSet();
|
|
@@ -41064,7 +41174,7 @@ class Evaluator {
|
|
|
41064
41174
|
this.setEvaluatedCell(positionId, evaluatedCell);
|
|
41065
41175
|
// check if formula dependencies present in the spread zone
|
|
41066
41176
|
// if so, they need to be recomputed
|
|
41067
|
-
this.nextPositionsToUpdate.
|
|
41177
|
+
this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([positionId]));
|
|
41068
41178
|
};
|
|
41069
41179
|
}
|
|
41070
41180
|
invalidateSpreading(positionId) {
|
|
@@ -41079,8 +41189,8 @@ class Evaluator {
|
|
|
41079
41189
|
continue;
|
|
41080
41190
|
}
|
|
41081
41191
|
this.evaluatedCells.delete(child);
|
|
41082
|
-
this.nextPositionsToUpdate.
|
|
41083
|
-
this.nextPositionsToUpdate.
|
|
41192
|
+
this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([child]));
|
|
41193
|
+
this.nextPositionsToUpdate.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(child));
|
|
41084
41194
|
}
|
|
41085
41195
|
this.spreadingRelations.removeNode(positionId);
|
|
41086
41196
|
}
|
|
@@ -41429,7 +41539,13 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
41429
41539
|
const format = newFormat
|
|
41430
41540
|
? getItemId(newFormat, data.formats)
|
|
41431
41541
|
: exportedCellData.format;
|
|
41432
|
-
|
|
41542
|
+
let content;
|
|
41543
|
+
if (formulaCell instanceof FormulaCellWithDependencies) {
|
|
41544
|
+
content = this.getters.getFormulaCellContent(exportedSheetData.id, formulaCell.compiledFormula, formulaCell.compiledFormula.dependencies, true);
|
|
41545
|
+
}
|
|
41546
|
+
else {
|
|
41547
|
+
content = !isExported ? newContent : exportedCellData.content;
|
|
41548
|
+
}
|
|
41433
41549
|
exportedSheetData.cells[xc] = { ...exportedCellData, value, isFormula, content, format };
|
|
41434
41550
|
}
|
|
41435
41551
|
}
|
|
@@ -50745,6 +50861,16 @@ class ImageProvider {
|
|
|
50745
50861
|
}
|
|
50746
50862
|
}
|
|
50747
50863
|
|
|
50864
|
+
class FocusableElement {
|
|
50865
|
+
focusableElement = undefined;
|
|
50866
|
+
setFocusableElement(element) {
|
|
50867
|
+
this.focusableElement = element;
|
|
50868
|
+
}
|
|
50869
|
+
focus() {
|
|
50870
|
+
this.focusableElement?.focus();
|
|
50871
|
+
}
|
|
50872
|
+
}
|
|
50873
|
+
|
|
50748
50874
|
const RIPPLE_KEY_FRAMES = [
|
|
50749
50875
|
{ transform: "scale(0)" },
|
|
50750
50876
|
{ transform: "scale(0.8)", offset: 0.33 },
|
|
@@ -52901,6 +53027,7 @@ class Spreadsheet extends owl.Component {
|
|
|
52901
53027
|
toggleSidePanel: this.toggleSidePanel.bind(this),
|
|
52902
53028
|
clipboard: this.env.clipboard || instantiateClipboard(),
|
|
52903
53029
|
startCellEdition: (content) => this.onGridComposerCellFocused(content),
|
|
53030
|
+
focusableElement: new FocusableElement(),
|
|
52904
53031
|
});
|
|
52905
53032
|
owl.useExternalListener(window, "resize", () => this.render(true));
|
|
52906
53033
|
owl.useExternalListener(window, "beforeunload", this.unbindModelEvents.bind(this));
|
|
@@ -53007,16 +53134,17 @@ class Spreadsheet extends owl.Component {
|
|
|
53007
53134
|
}
|
|
53008
53135
|
this.composer.topBarFocus = "contentFocus";
|
|
53009
53136
|
this.composer.gridFocusMode = "inactive";
|
|
53010
|
-
this.setComposerContent({ selection }
|
|
53137
|
+
this.setComposerContent({ selection });
|
|
53011
53138
|
}
|
|
53012
|
-
onGridComposerContentFocused() {
|
|
53139
|
+
onGridComposerContentFocused(selection) {
|
|
53013
53140
|
if (this.model.getters.isReadonly()) {
|
|
53014
53141
|
return;
|
|
53015
53142
|
}
|
|
53016
53143
|
this.composer.topBarFocus = "inactive";
|
|
53017
53144
|
this.composer.gridFocusMode = "contentFocus";
|
|
53018
|
-
this.setComposerContent({});
|
|
53145
|
+
this.setComposerContent({ selection });
|
|
53019
53146
|
}
|
|
53147
|
+
// TODO: either both are defined or none of them. change those args to an object
|
|
53020
53148
|
onGridComposerCellFocused(content, selection) {
|
|
53021
53149
|
if (this.model.getters.isReadonly()) {
|
|
53022
53150
|
return;
|
|
@@ -54442,11 +54570,10 @@ class SelectionStreamProcessorImpl {
|
|
|
54442
54570
|
* next cluster if the given cell is outside a cluster or at the border of a cluster in the given direction.
|
|
54443
54571
|
*/
|
|
54444
54572
|
getEndOfCluster(startPosition, dim, dir) {
|
|
54445
|
-
const sheet = this.getters.getActiveSheet();
|
|
54446
54573
|
let currentPosition = startPosition;
|
|
54447
54574
|
// If both the current cell and the next cell are not empty, we want to go to the end of the cluster
|
|
54448
54575
|
const nextCellPosition = this.getNextCellPosition(startPosition, dim, dir);
|
|
54449
|
-
let mode = !this.
|
|
54576
|
+
let mode = !this.isEvaluatedCellEmpty(currentPosition) && !this.isEvaluatedCellEmpty(nextCellPosition)
|
|
54450
54577
|
? "endOfCluster"
|
|
54451
54578
|
: "nextCluster";
|
|
54452
54579
|
while (true) {
|
|
@@ -54456,7 +54583,7 @@ class SelectionStreamProcessorImpl {
|
|
|
54456
54583
|
currentPosition.row === nextCellPosition.row) {
|
|
54457
54584
|
break;
|
|
54458
54585
|
}
|
|
54459
|
-
const isNextCellEmpty = this.
|
|
54586
|
+
const isNextCellEmpty = this.isEvaluatedCellEmpty(nextCellPosition);
|
|
54460
54587
|
if (mode === "endOfCluster" && isNextCellEmpty) {
|
|
54461
54588
|
break;
|
|
54462
54589
|
}
|
|
@@ -54470,10 +54597,20 @@ class SelectionStreamProcessorImpl {
|
|
|
54470
54597
|
return dim === "cols" ? currentPosition.col : currentPosition.row;
|
|
54471
54598
|
}
|
|
54472
54599
|
/**
|
|
54473
|
-
*
|
|
54474
|
-
* check
|
|
54600
|
+
* Checks if a cell is empty (i.e. does not have a content). If the cell is part of a merge,
|
|
54601
|
+
* the check applies to the main cell of the merge.
|
|
54475
54602
|
*/
|
|
54476
|
-
isCellEmpty({ col, row }
|
|
54603
|
+
isCellEmpty({ col, row }) {
|
|
54604
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
54605
|
+
const position = this.getters.getMainCellPosition({ sheetId, col, row });
|
|
54606
|
+
return !(this.getters.getCorrespondingFormulaCell(position) || this.getters.getCell(position)?.content);
|
|
54607
|
+
}
|
|
54608
|
+
/**
|
|
54609
|
+
* Checks if a cell evaluated value is empty. If the cell is part of a merge,
|
|
54610
|
+
* the check applies to the main cell of the merge.
|
|
54611
|
+
*/
|
|
54612
|
+
isEvaluatedCellEmpty({ col, row }) {
|
|
54613
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
54477
54614
|
const position = this.getters.getMainCellPosition({ sheetId, col, row });
|
|
54478
54615
|
const cell = this.getters.getEvaluatedCell(position);
|
|
54479
54616
|
return cell.type === CellValueType.empty;
|
|
@@ -54951,12 +55088,7 @@ function addFormula(cell) {
|
|
|
54951
55088
|
attrs.push(["t", "str"]);
|
|
54952
55089
|
cycle = escapeXml /*xml*/ `<v>${cell.value}</v>`;
|
|
54953
55090
|
}
|
|
54954
|
-
node = escapeXml /*xml*/
|
|
54955
|
-
<f>
|
|
54956
|
-
${XlsxFormula}
|
|
54957
|
-
</f>
|
|
54958
|
-
${cycle}
|
|
54959
|
-
`;
|
|
55091
|
+
node = escapeXml /*xml*/ `<f>${XlsxFormula}</f>${cycle}`;
|
|
54960
55092
|
return { attrs, node };
|
|
54961
55093
|
}
|
|
54962
55094
|
function addContent(content, sharedStrings, forceString = false) {
|
|
@@ -55775,11 +55907,10 @@ function addRows(construct, data, sheet) {
|
|
|
55775
55907
|
({ attrs: additionalAttrs, node: cellNode } = addContent(cell.content, construct.sharedStrings, isTableHeader));
|
|
55776
55908
|
}
|
|
55777
55909
|
attributes.push(...additionalAttrs);
|
|
55778
|
-
|
|
55779
|
-
|
|
55780
|
-
|
|
55781
|
-
|
|
55782
|
-
`);
|
|
55910
|
+
// prettier-ignore
|
|
55911
|
+
cellNodes.push(escapeXml /*xml*/ `<c ${formatAttributes(attributes)}>
|
|
55912
|
+
${cellNode}
|
|
55913
|
+
</c>`);
|
|
55783
55914
|
}
|
|
55784
55915
|
}
|
|
55785
55916
|
if (cellNodes.length || row.size !== DEFAULT_CELL_HEIGHT || row.isHidden) {
|
|
@@ -56375,7 +56506,6 @@ class Model extends EventBus {
|
|
|
56375
56506
|
...config,
|
|
56376
56507
|
mode: config.mode || "normal",
|
|
56377
56508
|
custom: config.custom || {},
|
|
56378
|
-
defaultCurrencyFormat: config.defaultCurrencyFormat || "[$$]#,##0.00",
|
|
56379
56509
|
external: this.setupExternalConfig(config.external || {}),
|
|
56380
56510
|
transportService,
|
|
56381
56511
|
client,
|
|
@@ -56413,6 +56543,7 @@ class Model extends EventBus {
|
|
|
56413
56543
|
custom: this.config.custom,
|
|
56414
56544
|
uiActions: this.config,
|
|
56415
56545
|
session: this.session,
|
|
56546
|
+
defaultCurrencyFormat: this.config.defaultCurrencyFormat,
|
|
56416
56547
|
};
|
|
56417
56548
|
}
|
|
56418
56549
|
// ---------------------------------------------------------------------------
|
|
@@ -56785,6 +56916,6 @@ exports.setTranslationMethod = setTranslationMethod;
|
|
|
56785
56916
|
exports.tokenize = tokenize;
|
|
56786
56917
|
|
|
56787
56918
|
|
|
56788
|
-
__info__.version = "17.0.
|
|
56789
|
-
__info__.date = "2024-
|
|
56790
|
-
__info__.hash = "
|
|
56919
|
+
__info__.version = "17.0.12";
|
|
56920
|
+
__info__.date = "2024-02-16T14:24:02.984Z";
|
|
56921
|
+
__info__.hash = "8fa2bab";
|