@odoo/o-spreadsheet 18.2.0 → 18.3.0-alpha.1
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 +354 -290
- package/dist/o-spreadsheet.d.ts +28 -19
- package/dist/o-spreadsheet.esm.js +354 -290
- package/dist/o-spreadsheet.iife.js +354 -290
- package/dist/o-spreadsheet.iife.min.js +370 -370
- package/dist/o_spreadsheet.xml +7 -4
- package/package.json +3 -2
|
@@ -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 18.
|
|
6
|
-
* @date 2025-02-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 18.3.0-alpha.1
|
|
6
|
+
* @date 2025-02-25T06:00:14.885Z
|
|
7
|
+
* @hash be4d957
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
'use strict';
|
|
@@ -994,6 +994,9 @@ function getUniqueText(text, texts, options = {}) {
|
|
|
994
994
|
}
|
|
995
995
|
return newText;
|
|
996
996
|
}
|
|
997
|
+
function isFormula(content) {
|
|
998
|
+
return content.startsWith("=") || content.startsWith("+");
|
|
999
|
+
}
|
|
997
1000
|
|
|
998
1001
|
const RBA_REGEX = /rgba?\(|\s+|\)/gi;
|
|
999
1002
|
const HEX_MATCH = /^#([A-F\d]{2}){3,4}$/;
|
|
@@ -4460,7 +4463,7 @@ function dichotomicSearch(data, target, mode, sortOrder, rangeLength, getValueIn
|
|
|
4460
4463
|
* @param reverseSearch if true, search in the array starting from the end.
|
|
4461
4464
|
|
|
4462
4465
|
*/
|
|
4463
|
-
function linearSearch(data, target, mode, numberOfValues, getValueInData, reverseSearch = false) {
|
|
4466
|
+
function linearSearch(data, target, mode, numberOfValues, getValueInData, lookupCaches, reverseSearch = false) {
|
|
4464
4467
|
if (target === undefined || target.value === null) {
|
|
4465
4468
|
return -1;
|
|
4466
4469
|
}
|
|
@@ -4469,17 +4472,48 @@ function linearSearch(data, target, mode, numberOfValues, getValueInData, revers
|
|
|
4469
4472
|
}
|
|
4470
4473
|
const _target = normalizeValue(target.value);
|
|
4471
4474
|
const getValue = reverseSearch
|
|
4472
|
-
? (data, i) => getValueInData(data, numberOfValues - i - 1)
|
|
4473
|
-
: getValueInData;
|
|
4475
|
+
? (data, i) => normalizeValue(getValueInData(data, numberOfValues - i - 1))
|
|
4476
|
+
: (data, i) => normalizeValue(getValueInData(data, i));
|
|
4477
|
+
// first check if the target is in the cache
|
|
4478
|
+
const isNotWildcardTarget = mode !== "wildcard" ||
|
|
4479
|
+
typeof _target !== "string" ||
|
|
4480
|
+
!(_target.includes("*") || _target.includes("?"));
|
|
4481
|
+
if (lookupCaches && isNotWildcardTarget) {
|
|
4482
|
+
const searchMode = reverseSearch ? "reverseSearch" : "forwardSearch";
|
|
4483
|
+
let cache = lookupCaches[searchMode].get(data);
|
|
4484
|
+
if (cache === undefined) {
|
|
4485
|
+
// build the cache for all the values
|
|
4486
|
+
cache = new Map();
|
|
4487
|
+
for (let i = 0; i < numberOfValues; i++) {
|
|
4488
|
+
const value = getValue(data, i) ?? null;
|
|
4489
|
+
if (!cache.has(value)) {
|
|
4490
|
+
cache.set(value, i);
|
|
4491
|
+
}
|
|
4492
|
+
}
|
|
4493
|
+
lookupCaches[searchMode].set(data, cache);
|
|
4494
|
+
}
|
|
4495
|
+
if (cache.has(_target)) {
|
|
4496
|
+
const resultIndex = cache.get(_target);
|
|
4497
|
+
return reverseSearch ? numberOfValues - resultIndex - 1 : resultIndex;
|
|
4498
|
+
}
|
|
4499
|
+
if (mode === "strict") {
|
|
4500
|
+
return -1;
|
|
4501
|
+
}
|
|
4502
|
+
}
|
|
4503
|
+
// else perform the linear search
|
|
4504
|
+
const resultIndex = _linearSearch(data, _target, mode, numberOfValues, getValue);
|
|
4505
|
+
return reverseSearch && resultIndex !== -1 ? numberOfValues - resultIndex - 1 : resultIndex;
|
|
4506
|
+
}
|
|
4507
|
+
function _linearSearch(data, _target, mode, numberOfValues, getNormalizeValue) {
|
|
4474
4508
|
let indexMatchTarget = (i) => {
|
|
4475
|
-
return
|
|
4509
|
+
return getNormalizeValue(data, i) === _target;
|
|
4476
4510
|
};
|
|
4477
4511
|
if (mode === "wildcard" &&
|
|
4478
4512
|
typeof _target === "string" &&
|
|
4479
4513
|
(_target.includes("*") || _target.includes("?"))) {
|
|
4480
4514
|
const regExp = wildcardToRegExp(_target);
|
|
4481
4515
|
indexMatchTarget = (i) => {
|
|
4482
|
-
const value =
|
|
4516
|
+
const value = getNormalizeValue(data, i);
|
|
4483
4517
|
if (typeof value === "string") {
|
|
4484
4518
|
return regExp.test(value);
|
|
4485
4519
|
}
|
|
@@ -4490,7 +4524,7 @@ function linearSearch(data, target, mode, numberOfValues, getValueInData, revers
|
|
|
4490
4524
|
let closestMatchIndex = -1;
|
|
4491
4525
|
if (mode === "nextSmaller") {
|
|
4492
4526
|
indexMatchTarget = (i) => {
|
|
4493
|
-
const value =
|
|
4527
|
+
const value = getNormalizeValue(data, i);
|
|
4494
4528
|
if ((!closestMatch && compareCellValues(_target, value) >= 0) ||
|
|
4495
4529
|
(compareCellValues(_target, value) >= 0 && compareCellValues(value, closestMatch) > 0)) {
|
|
4496
4530
|
closestMatch = value;
|
|
@@ -4501,7 +4535,7 @@ function linearSearch(data, target, mode, numberOfValues, getValueInData, revers
|
|
|
4501
4535
|
}
|
|
4502
4536
|
if (mode === "nextGreater") {
|
|
4503
4537
|
indexMatchTarget = (i) => {
|
|
4504
|
-
const value =
|
|
4538
|
+
const value = getNormalizeValue(data, i);
|
|
4505
4539
|
if ((!closestMatch && compareCellValues(_target, value) <= 0) ||
|
|
4506
4540
|
(compareCellValues(_target, value) <= 0 && compareCellValues(value, closestMatch) < 0)) {
|
|
4507
4541
|
closestMatch = value;
|
|
@@ -4512,12 +4546,10 @@ function linearSearch(data, target, mode, numberOfValues, getValueInData, revers
|
|
|
4512
4546
|
}
|
|
4513
4547
|
for (let i = 0; i < numberOfValues; i++) {
|
|
4514
4548
|
if (indexMatchTarget(i)) {
|
|
4515
|
-
return
|
|
4549
|
+
return i;
|
|
4516
4550
|
}
|
|
4517
4551
|
}
|
|
4518
|
-
return
|
|
4519
|
-
? numberOfValues - closestMatchIndex - 1
|
|
4520
|
-
: closestMatchIndex;
|
|
4552
|
+
return closestMatchIndex;
|
|
4521
4553
|
}
|
|
4522
4554
|
/**
|
|
4523
4555
|
* Normalize a value.
|
|
@@ -4633,8 +4665,8 @@ function findMatchingSpec(url) {
|
|
|
4633
4665
|
function urlRepresentation(link, getters) {
|
|
4634
4666
|
return findMatchingSpec(link.url).urlRepresentation(link.url, getters);
|
|
4635
4667
|
}
|
|
4636
|
-
function openLink(link, env) {
|
|
4637
|
-
findMatchingSpec(link.url).open(link.url, env);
|
|
4668
|
+
function openLink(link, env, isMiddleClick) {
|
|
4669
|
+
findMatchingSpec(link.url).open(link.url, env, isMiddleClick);
|
|
4638
4670
|
}
|
|
4639
4671
|
function detectLink(value) {
|
|
4640
4672
|
if (typeof value !== "string") {
|
|
@@ -6491,10 +6523,11 @@ class UuidGenerator {
|
|
|
6491
6523
|
*
|
|
6492
6524
|
*/
|
|
6493
6525
|
smallUuid() {
|
|
6494
|
-
|
|
6495
|
-
|
|
6496
|
-
|
|
6497
|
-
|
|
6526
|
+
if (window.crypto) {
|
|
6527
|
+
return "10000000-1000".replace(/[01]/g, (c) => {
|
|
6528
|
+
const n = Number(c);
|
|
6529
|
+
return (n ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (n / 4)))).toString(16);
|
|
6530
|
+
});
|
|
6498
6531
|
}
|
|
6499
6532
|
else {
|
|
6500
6533
|
// mainly for jest and other browsers that do not have the crypto functionality
|
|
@@ -6509,10 +6542,11 @@ class UuidGenerator {
|
|
|
6509
6542
|
* This method should be used when you need to avoid collisions at all costs, like the id of a revision.
|
|
6510
6543
|
*/
|
|
6511
6544
|
uuidv4() {
|
|
6512
|
-
|
|
6513
|
-
|
|
6514
|
-
|
|
6515
|
-
|
|
6545
|
+
if (window.crypto) {
|
|
6546
|
+
return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, (c) => {
|
|
6547
|
+
const n = Number(c);
|
|
6548
|
+
return (n ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (n / 4)))).toString(16);
|
|
6549
|
+
});
|
|
6516
6550
|
}
|
|
6517
6551
|
else {
|
|
6518
6552
|
// mainly for jest and other browsers that do not have the crypto functionality
|
|
@@ -6920,7 +6954,7 @@ function isValidLocale(locale) {
|
|
|
6920
6954
|
* canonicalizeNumberContent("02/12/2012", FR_LOCALE) // "02/12/2012"
|
|
6921
6955
|
*/
|
|
6922
6956
|
function canonicalizeNumberContent(content, locale) {
|
|
6923
|
-
return content
|
|
6957
|
+
return isFormula(content)
|
|
6924
6958
|
? canonicalizeFormula$1(content, locale)
|
|
6925
6959
|
: canonicalizeNumberLiteral(content, locale);
|
|
6926
6960
|
}
|
|
@@ -6935,7 +6969,7 @@ function canonicalizeNumberContent(content, locale) {
|
|
|
6935
6969
|
* canonicalizeContent("02-12-2012", FR_LOCALE) // "12/02/2012"
|
|
6936
6970
|
*/
|
|
6937
6971
|
function canonicalizeContent(content, locale) {
|
|
6938
|
-
return content
|
|
6972
|
+
return isFormula(content)
|
|
6939
6973
|
? canonicalizeFormula$1(content, locale)
|
|
6940
6974
|
: canonicalizeLiteral(content, locale);
|
|
6941
6975
|
}
|
|
@@ -6954,7 +6988,7 @@ function localizeContent(content, locale) {
|
|
|
6954
6988
|
}
|
|
6955
6989
|
/** Change a formula to its canonical form (en_US locale) */
|
|
6956
6990
|
function canonicalizeFormula$1(formula, locale) {
|
|
6957
|
-
return _localizeFormula$1(formula, locale, DEFAULT_LOCALE);
|
|
6991
|
+
return _localizeFormula$1(formula.startsWith("+") ? "=" + formula.slice(1) : formula, locale, DEFAULT_LOCALE);
|
|
6958
6992
|
}
|
|
6959
6993
|
/** Change a formula from the canonical form to the given locale */
|
|
6960
6994
|
function localizeFormula(formula, locale) {
|
|
@@ -7117,13 +7151,13 @@ function getDateTimeFormat(locale) {
|
|
|
7117
7151
|
|
|
7118
7152
|
/** Change a number string to its canonical form (en_US locale) */
|
|
7119
7153
|
function canonicalizeNumberValue(content, locale) {
|
|
7120
|
-
return content
|
|
7154
|
+
return isFormula(content)
|
|
7121
7155
|
? canonicalizeFormula(content, locale)
|
|
7122
7156
|
: canonicalizeNumberLiteral(content, locale);
|
|
7123
7157
|
}
|
|
7124
7158
|
/** Change a formula to its canonical form (en_US locale) */
|
|
7125
7159
|
function canonicalizeFormula(formula, locale) {
|
|
7126
|
-
return _localizeFormula(formula, locale, DEFAULT_LOCALE);
|
|
7160
|
+
return _localizeFormula(formula.startsWith("+") ? "=" + formula.slice(1) : formula, locale, DEFAULT_LOCALE);
|
|
7127
7161
|
}
|
|
7128
7162
|
function _localizeFormula(formula, fromLocale, toLocale) {
|
|
7129
7163
|
if (fromLocale.formulaArgSeparator === toLocale.formulaArgSeparator &&
|
|
@@ -10877,7 +10911,7 @@ const autoCompleteProviders = new Registry();
|
|
|
10877
10911
|
|
|
10878
10912
|
autoCompleteProviders.add("dataValidation", {
|
|
10879
10913
|
getProposals(tokenAtCursor, content) {
|
|
10880
|
-
if (content
|
|
10914
|
+
if (isFormula(content)) {
|
|
10881
10915
|
return [];
|
|
10882
10916
|
}
|
|
10883
10917
|
if (!this.composer.currentEditedCell) {
|
|
@@ -18686,7 +18720,7 @@ const HLOOKUP = {
|
|
|
18686
18720
|
const _isSorted = toBoolean(isSorted.value);
|
|
18687
18721
|
const colIndex = _isSorted
|
|
18688
18722
|
? dichotomicSearch(_range, searchKey, "nextSmaller", "asc", _range.length, getValueFromRange)
|
|
18689
|
-
: linearSearch(_range, searchKey, "wildcard", _range.length, getValueFromRange);
|
|
18723
|
+
: linearSearch(_range, searchKey, "wildcard", _range.length, getValueFromRange, this.lookupCaches);
|
|
18690
18724
|
const col = _range[colIndex];
|
|
18691
18725
|
if (col === undefined) {
|
|
18692
18726
|
return valueNotAvailable(searchKey);
|
|
@@ -18841,7 +18875,7 @@ const MATCH = {
|
|
|
18841
18875
|
index = dichotomicSearch(_range, searchKey, "nextSmaller", "asc", rangeLen, getElement);
|
|
18842
18876
|
break;
|
|
18843
18877
|
case 0:
|
|
18844
|
-
index = linearSearch(_range, searchKey, "wildcard", rangeLen, getElement);
|
|
18878
|
+
index = linearSearch(_range, searchKey, "wildcard", rangeLen, getElement, this.lookupCaches);
|
|
18845
18879
|
break;
|
|
18846
18880
|
case -1:
|
|
18847
18881
|
index = dichotomicSearch(_range, searchKey, "nextGreater", "desc", rangeLen, getElement);
|
|
@@ -18909,7 +18943,7 @@ const VLOOKUP = {
|
|
|
18909
18943
|
const _isSorted = toBoolean(isSorted.value);
|
|
18910
18944
|
const rowIndex = _isSorted
|
|
18911
18945
|
? dichotomicSearch(_range, searchKey, "nextSmaller", "asc", _range[0].length, getValueFromRange)
|
|
18912
|
-
: linearSearch(_range, searchKey, "wildcard", _range[0].length, getValueFromRange);
|
|
18946
|
+
: linearSearch(_range, searchKey, "wildcard", _range[0].length, getValueFromRange, this.lookupCaches);
|
|
18913
18947
|
const value = _range[_index - 1][rowIndex];
|
|
18914
18948
|
if (value === undefined) {
|
|
18915
18949
|
return valueNotAvailable(searchKey);
|
|
@@ -18965,7 +18999,7 @@ const XLOOKUP = {
|
|
|
18965
18999
|
const reverseSearch = _searchMode === -1;
|
|
18966
19000
|
const index = _searchMode === 2 || _searchMode === -2
|
|
18967
19001
|
? dichotomicSearch(_lookupRange, searchKey, mode, _searchMode === 2 ? "asc" : "desc", rangeLen, getElement)
|
|
18968
|
-
: linearSearch(_lookupRange, searchKey, mode, rangeLen, getElement, reverseSearch);
|
|
19002
|
+
: linearSearch(_lookupRange, searchKey, mode, rangeLen, getElement, this.lookupCaches, reverseSearch);
|
|
18969
19003
|
if (index !== -1) {
|
|
18970
19004
|
return lookupDirection === "col"
|
|
18971
19005
|
? _returnRange.map((col) => [col[index]])
|
|
@@ -20423,7 +20457,7 @@ autoCompleteProviders.add("functions", {
|
|
|
20423
20457
|
return [];
|
|
20424
20458
|
}
|
|
20425
20459
|
const searchTerm = tokenAtCursor.value;
|
|
20426
|
-
if (!this.composer.currentContent
|
|
20460
|
+
if (!isFormula(this.composer.currentContent)) {
|
|
20427
20461
|
return [];
|
|
20428
20462
|
}
|
|
20429
20463
|
const values = Object.entries(functionRegistry.content)
|
|
@@ -20831,7 +20865,7 @@ class AbstractComposerStore extends SpreadsheetStore {
|
|
|
20831
20865
|
return;
|
|
20832
20866
|
}
|
|
20833
20867
|
if (content) {
|
|
20834
|
-
if (content
|
|
20868
|
+
if (isFormula(content)) {
|
|
20835
20869
|
const left = this.currentTokens.filter((t) => t.type === "LEFT_PAREN").length;
|
|
20836
20870
|
const right = this.currentTokens.filter((t) => t.type === "RIGHT_PAREN").length;
|
|
20837
20871
|
const missing = left - right;
|
|
@@ -20885,7 +20919,7 @@ class AbstractComposerStore extends SpreadsheetStore {
|
|
|
20885
20919
|
}
|
|
20886
20920
|
if (isNewCurrentContent || this.editionMode !== "inactive") {
|
|
20887
20921
|
const locale = this.getters.getLocale();
|
|
20888
|
-
this.currentTokens = text
|
|
20922
|
+
this.currentTokens = isFormula(text) ? composerTokenize(text, locale) : [];
|
|
20889
20923
|
if (this.currentTokens.length > 100) {
|
|
20890
20924
|
if (raise) {
|
|
20891
20925
|
this.notificationStore.raiseError(_t("This formula has over 100 parts. It can't be processed properly, consider splitting it into multiple cells"));
|
|
@@ -21085,7 +21119,7 @@ class AbstractComposerStore extends SpreadsheetStore {
|
|
|
21085
21119
|
}
|
|
21086
21120
|
}
|
|
21087
21121
|
updateRangeColor() {
|
|
21088
|
-
if (!this._currentContent
|
|
21122
|
+
if (!isFormula(this._currentContent) || this.editionMode === "inactive") {
|
|
21089
21123
|
return;
|
|
21090
21124
|
}
|
|
21091
21125
|
const editionSheetId = this.sheetId;
|
|
@@ -21114,7 +21148,7 @@ class AbstractComposerStore extends SpreadsheetStore {
|
|
|
21114
21148
|
* Highlight all ranges that can be found in the composer content.
|
|
21115
21149
|
*/
|
|
21116
21150
|
get highlights() {
|
|
21117
|
-
if (!this.currentContent
|
|
21151
|
+
if (!isFormula(this.currentContent) || this.editionMode === "inactive") {
|
|
21118
21152
|
return [];
|
|
21119
21153
|
}
|
|
21120
21154
|
const editionSheetId = this.sheetId;
|
|
@@ -21148,7 +21182,7 @@ class AbstractComposerStore extends SpreadsheetStore {
|
|
|
21148
21182
|
}
|
|
21149
21183
|
get autocompleteProvider() {
|
|
21150
21184
|
const content = this.currentContent;
|
|
21151
|
-
const tokenAtCursor = content
|
|
21185
|
+
const tokenAtCursor = isFormula(content)
|
|
21152
21186
|
? this.tokenAtCursor
|
|
21153
21187
|
: { type: "STRING", value: content };
|
|
21154
21188
|
if (this.editionMode === "inactive" ||
|
|
@@ -21205,7 +21239,7 @@ class AbstractComposerStore extends SpreadsheetStore {
|
|
|
21205
21239
|
* - Previous and next tokens can be separated by spaces
|
|
21206
21240
|
*/
|
|
21207
21241
|
canStartComposerRangeSelection() {
|
|
21208
|
-
if (this._currentContent
|
|
21242
|
+
if (isFormula(this._currentContent)) {
|
|
21209
21243
|
const tokenAtCursor = this.tokenAtCursor;
|
|
21210
21244
|
if (!tokenAtCursor) {
|
|
21211
21245
|
return false;
|
|
@@ -28304,7 +28338,7 @@ function getBarChartData(definition, dataSets, labelRange, getters) {
|
|
|
28304
28338
|
}
|
|
28305
28339
|
function getPyramidChartData(definition, dataSets, labelRange, getters) {
|
|
28306
28340
|
const barChartData = getBarChartData(definition, dataSets, labelRange, getters);
|
|
28307
|
-
const barDataset = barChartData.dataSetsValues;
|
|
28341
|
+
const barDataset = barChartData.dataSetsValues.filter((ds) => !ds.hidden);
|
|
28308
28342
|
const pyramidDatasetValues = [];
|
|
28309
28343
|
if (barDataset[0]) {
|
|
28310
28344
|
const pyramidData = barDataset[0].data.map((value) => (value > 0 ? value : 0));
|
|
@@ -28781,10 +28815,8 @@ function getChartDatasetFormat(getters, allDataSets, axis) {
|
|
|
28781
28815
|
function getChartDatasetValues(getters, dataSets) {
|
|
28782
28816
|
const datasetValues = [];
|
|
28783
28817
|
for (const [dsIndex, ds] of Object.entries(dataSets)) {
|
|
28784
|
-
if (getters.isColHidden(ds.dataRange.sheetId, ds.dataRange.zone.left)) {
|
|
28785
|
-
continue;
|
|
28786
|
-
}
|
|
28787
28818
|
let label;
|
|
28819
|
+
let hidden = getters.isColHidden(ds.dataRange.sheetId, ds.dataRange.zone.left);
|
|
28788
28820
|
if (ds.labelCell) {
|
|
28789
28821
|
const labelRange = ds.labelCell;
|
|
28790
28822
|
const cell = labelRange
|
|
@@ -28811,9 +28843,9 @@ function getChartDatasetValues(getters, dataSets) {
|
|
|
28811
28843
|
data.fill(1);
|
|
28812
28844
|
}
|
|
28813
28845
|
else if (data.every((cell) => cell === undefined || cell === null || !isNumber(cell.toString(), DEFAULT_LOCALE))) {
|
|
28814
|
-
|
|
28846
|
+
hidden = true;
|
|
28815
28847
|
}
|
|
28816
|
-
datasetValues.push({ data, label });
|
|
28848
|
+
datasetValues.push({ data, label, hidden });
|
|
28817
28849
|
}
|
|
28818
28850
|
return datasetValues;
|
|
28819
28851
|
}
|
|
@@ -28824,12 +28856,13 @@ function getBarChartDatasets(definition, args) {
|
|
|
28824
28856
|
const colors = getChartColorsGenerator(definition, dataSetsValues.length);
|
|
28825
28857
|
const trendDatasets = [];
|
|
28826
28858
|
for (const index in dataSetsValues) {
|
|
28827
|
-
let { label, data } = dataSetsValues[index];
|
|
28859
|
+
let { label, data, hidden } = dataSetsValues[index];
|
|
28828
28860
|
label = definition.dataSets?.[index].label || label;
|
|
28829
28861
|
const backgroundColor = colors.next();
|
|
28830
28862
|
const dataset = {
|
|
28831
28863
|
label,
|
|
28832
28864
|
data,
|
|
28865
|
+
hidden,
|
|
28833
28866
|
borderColor: definition.background || BACKGROUND_CHART_COLOR,
|
|
28834
28867
|
borderWidth: definition.stacked ? 1 : 0,
|
|
28835
28868
|
backgroundColor,
|
|
@@ -28862,6 +28895,9 @@ function getWaterfallDatasetAndLabels(definition, args) {
|
|
|
28862
28895
|
const labelsWithSubTotals = [];
|
|
28863
28896
|
let lastValue = 0;
|
|
28864
28897
|
for (const dataSetsValue of dataSetsValues) {
|
|
28898
|
+
if (dataSetsValue.hidden) {
|
|
28899
|
+
continue;
|
|
28900
|
+
}
|
|
28865
28901
|
for (let i = 0; i < dataSetsValue.data.length; i++) {
|
|
28866
28902
|
const data = dataSetsValue.data[i];
|
|
28867
28903
|
labelsWithSubTotals.push(labels[i]);
|
|
@@ -28897,7 +28933,7 @@ function getLineChartDatasets(definition, args) {
|
|
|
28897
28933
|
const trendDatasets = [];
|
|
28898
28934
|
const colors = getChartColorsGenerator(definition, dataSetsValues.length);
|
|
28899
28935
|
for (let index = 0; index < dataSetsValues.length; index++) {
|
|
28900
|
-
let { label, data } = dataSetsValues[index];
|
|
28936
|
+
let { label, data, hidden } = dataSetsValues[index];
|
|
28901
28937
|
label = definition.dataSets?.[index].label || label;
|
|
28902
28938
|
const color = colors.next();
|
|
28903
28939
|
if (axisType && ["linear", "time"].includes(axisType)) {
|
|
@@ -28907,6 +28943,7 @@ function getLineChartDatasets(definition, args) {
|
|
|
28907
28943
|
const dataset = {
|
|
28908
28944
|
label,
|
|
28909
28945
|
data,
|
|
28946
|
+
hidden,
|
|
28910
28947
|
tension: 0, // 0 -> render straight lines, which is much faster
|
|
28911
28948
|
borderColor: color,
|
|
28912
28949
|
backgroundColor: areaChart ? setColorAlpha(color, LINE_FILL_TRANSPARENCY) : color,
|
|
@@ -28939,7 +28976,9 @@ function getPieChartDatasets(definition, args) {
|
|
|
28939
28976
|
const dataSets = [];
|
|
28940
28977
|
const dataSetsLength = Math.max(0, ...dataSetsValues.map((ds) => ds?.data?.length ?? 0));
|
|
28941
28978
|
const backgroundColor = getPieColors(new ColorGenerator(dataSetsLength), dataSetsValues);
|
|
28942
|
-
for (const { label, data } of dataSetsValues) {
|
|
28979
|
+
for (const { label, data, hidden } of dataSetsValues) {
|
|
28980
|
+
if (hidden)
|
|
28981
|
+
continue;
|
|
28943
28982
|
const dataset = {
|
|
28944
28983
|
label,
|
|
28945
28984
|
data,
|
|
@@ -28957,7 +28996,7 @@ function getComboChartDatasets(definition, args) {
|
|
|
28957
28996
|
const colors = getChartColorsGenerator(definition, dataSetsValues.length);
|
|
28958
28997
|
const trendDatasets = [];
|
|
28959
28998
|
for (let index = 0; index < dataSetsValues.length; index++) {
|
|
28960
|
-
let { label, data } = dataSetsValues[index];
|
|
28999
|
+
let { label, data, hidden } = dataSetsValues[index];
|
|
28961
29000
|
label = definition.dataSets?.[index].label || label;
|
|
28962
29001
|
const design = definition.dataSets?.[index];
|
|
28963
29002
|
const color = colors.next();
|
|
@@ -28965,6 +29004,7 @@ function getComboChartDatasets(definition, args) {
|
|
|
28965
29004
|
const dataset = {
|
|
28966
29005
|
label: label,
|
|
28967
29006
|
data,
|
|
29007
|
+
hidden,
|
|
28968
29008
|
borderColor: color,
|
|
28969
29009
|
backgroundColor: color,
|
|
28970
29010
|
yAxisID: definition.dataSets?.[index].yAxisId || "y",
|
|
@@ -28989,7 +29029,7 @@ function getRadarChartDatasets(definition, args) {
|
|
|
28989
29029
|
const fill = definition.fillArea ?? false;
|
|
28990
29030
|
const colors = getChartColorsGenerator(definition, dataSetsValues.length);
|
|
28991
29031
|
for (let i = 0; i < dataSetsValues.length; i++) {
|
|
28992
|
-
let { label, data } = dataSetsValues[i];
|
|
29032
|
+
let { label, data, hidden } = dataSetsValues[i];
|
|
28993
29033
|
if (definition.dataSets?.[i]?.label) {
|
|
28994
29034
|
label = definition.dataSets[i].label;
|
|
28995
29035
|
}
|
|
@@ -28997,6 +29037,7 @@ function getRadarChartDatasets(definition, args) {
|
|
|
28997
29037
|
const dataset = {
|
|
28998
29038
|
label,
|
|
28999
29039
|
data,
|
|
29040
|
+
hidden,
|
|
29000
29041
|
borderColor,
|
|
29001
29042
|
backgroundColor: borderColor,
|
|
29002
29043
|
};
|
|
@@ -29142,6 +29183,11 @@ function getPieChartLegend(definition, args) {
|
|
|
29142
29183
|
hidden: false,
|
|
29143
29184
|
lineWidth: 2,
|
|
29144
29185
|
})),
|
|
29186
|
+
filter: (legendItem, data) => {
|
|
29187
|
+
return "datasetIndex" in legendItem
|
|
29188
|
+
? !data.datasets[legendItem.datasetIndex].hidden
|
|
29189
|
+
: true;
|
|
29190
|
+
},
|
|
29145
29191
|
},
|
|
29146
29192
|
};
|
|
29147
29193
|
}
|
|
@@ -29203,6 +29249,11 @@ function getWaterfallChartLegend(definition, args) {
|
|
|
29203
29249
|
}
|
|
29204
29250
|
return legendValues;
|
|
29205
29251
|
},
|
|
29252
|
+
filter: (legendItem, data) => {
|
|
29253
|
+
return "datasetIndex" in legendItem
|
|
29254
|
+
? !data.datasets[legendItem.datasetIndex].hidden
|
|
29255
|
+
: true;
|
|
29256
|
+
},
|
|
29206
29257
|
},
|
|
29207
29258
|
onClick: () => { }, // Disables click interaction with the waterfall chart legend items
|
|
29208
29259
|
};
|
|
@@ -29286,6 +29337,11 @@ function getCustomLegendLabels(fontColor, legendLabelConfig) {
|
|
|
29286
29337
|
...legendLabelConfig,
|
|
29287
29338
|
};
|
|
29288
29339
|
}),
|
|
29340
|
+
filter: (legendItem, data) => {
|
|
29341
|
+
return "datasetIndex" in legendItem
|
|
29342
|
+
? !data.datasets[legendItem.datasetIndex].hidden
|
|
29343
|
+
: true;
|
|
29344
|
+
},
|
|
29289
29345
|
},
|
|
29290
29346
|
};
|
|
29291
29347
|
}
|
|
@@ -29619,7 +29675,7 @@ const templates = /* xml */ `
|
|
|
29619
29675
|
<div
|
|
29620
29676
|
class="o-chart-custom-tooltip border rounded px-2 py-1 pe-none mw-100 position-absolute text-nowrap shadow opacity-100">
|
|
29621
29677
|
<table class="overflow-hidden m-0">
|
|
29622
|
-
<thead>
|
|
29678
|
+
<thead t-if="title">
|
|
29623
29679
|
<tr>
|
|
29624
29680
|
<th class="o-tooltip-title align-baseline border-0 text-truncate" t-esc="title" t-attf-style="max-width: {{ labelsMaxWidth }}"/>
|
|
29625
29681
|
</tr>
|
|
@@ -29680,8 +29736,8 @@ function getBarChartTooltip(definition, args) {
|
|
|
29680
29736
|
? undefined
|
|
29681
29737
|
: "";
|
|
29682
29738
|
},
|
|
29739
|
+
beforeLabel: (tooltipItem) => tooltipItem.dataset?.label || tooltipItem.label,
|
|
29683
29740
|
label: function (tooltipItem) {
|
|
29684
|
-
const xLabel = tooltipItem.dataset?.label || tooltipItem.label;
|
|
29685
29741
|
const horizontalChart = definition.horizontal;
|
|
29686
29742
|
let yLabel = horizontalChart ? tooltipItem.parsed.x : tooltipItem.parsed.y;
|
|
29687
29743
|
if (yLabel === undefined || yLabel === null) {
|
|
@@ -29689,7 +29745,7 @@ function getBarChartTooltip(definition, args) {
|
|
|
29689
29745
|
}
|
|
29690
29746
|
const axisId = horizontalChart ? tooltipItem.dataset.xAxisID : tooltipItem.dataset.yAxisID;
|
|
29691
29747
|
const yLabelStr = formatChartDatasetValue(args.axisFormats, args.locale)(yLabel, axisId);
|
|
29692
|
-
return
|
|
29748
|
+
return yLabelStr;
|
|
29693
29749
|
},
|
|
29694
29750
|
},
|
|
29695
29751
|
};
|
|
@@ -29714,21 +29770,18 @@ function getLineChartTooltip(definition, args) {
|
|
|
29714
29770
|
const formattedX = formatValue(label, { locale, format: labelFormat });
|
|
29715
29771
|
const axisId = tooltipItem.dataset.yAxisID || "y";
|
|
29716
29772
|
const formattedY = formatValue(dataSetPoint, { locale, format: axisFormats?.[axisId] });
|
|
29717
|
-
|
|
29718
|
-
return formattedX
|
|
29719
|
-
? `${dataSetTitle}: (${formattedX}, ${formattedY})`
|
|
29720
|
-
: `${dataSetTitle}: ${formattedY}`;
|
|
29773
|
+
return formattedX ? `(${formattedX}, ${formattedY})` : `${formattedY}`;
|
|
29721
29774
|
};
|
|
29722
29775
|
}
|
|
29723
29776
|
else {
|
|
29724
29777
|
tooltip.callbacks.label = function (tooltipItem) {
|
|
29725
|
-
const xLabel = tooltipItem.dataset?.label || tooltipItem.label;
|
|
29726
29778
|
const yLabel = tooltipItem.parsed.y;
|
|
29727
29779
|
const axisId = tooltipItem.dataset.yAxisID;
|
|
29728
29780
|
const yLabelStr = formatChartDatasetValue(axisFormats, locale)(yLabel, axisId);
|
|
29729
|
-
return
|
|
29781
|
+
return yLabelStr;
|
|
29730
29782
|
};
|
|
29731
29783
|
}
|
|
29784
|
+
tooltip.callbacks.beforeLabel = (tooltipItem) => tooltipItem.dataset?.label || tooltipItem.label;
|
|
29732
29785
|
tooltip.callbacks.title = function (tooltipItems) {
|
|
29733
29786
|
const displayTooltipTitle = axisType !== "linear" &&
|
|
29734
29787
|
tooltipItems.some((item) => item.dataset.xAxisID !== TREND_LINE_XAXIS_ID);
|
|
@@ -29746,17 +29799,15 @@ function getPieChartTooltip(definition, args) {
|
|
|
29746
29799
|
title: function (tooltipItems) {
|
|
29747
29800
|
return tooltipItems[0].dataset.label;
|
|
29748
29801
|
},
|
|
29802
|
+
beforeLabel: (tooltipItem) => tooltipItem.label || tooltipItem.dataset.label,
|
|
29749
29803
|
label: function (tooltipItem) {
|
|
29750
29804
|
const data = tooltipItem.dataset.data;
|
|
29751
29805
|
const dataIndex = tooltipItem.dataIndex;
|
|
29752
29806
|
const percentage = calculatePercentage(data, dataIndex);
|
|
29753
|
-
const xLabel = tooltipItem.label || tooltipItem.dataset.label;
|
|
29754
29807
|
const yLabel = tooltipItem.parsed.y ?? tooltipItem.parsed;
|
|
29755
29808
|
const toolTipFormat = !format && yLabel >= 1000 ? "#,##" : format;
|
|
29756
29809
|
const yLabelStr = formatValue(yLabel, { format: toolTipFormat, locale });
|
|
29757
|
-
return
|
|
29758
|
-
? `${xLabel}: ${yLabelStr} (${percentage}%)`
|
|
29759
|
-
: `${yLabelStr} (${percentage}%)`;
|
|
29810
|
+
return `${yLabelStr} (${percentage}%)`;
|
|
29760
29811
|
},
|
|
29761
29812
|
},
|
|
29762
29813
|
};
|
|
@@ -29769,16 +29820,17 @@ function getWaterfallChartTooltip(definition, args) {
|
|
|
29769
29820
|
enabled: false,
|
|
29770
29821
|
external: customTooltipHandler,
|
|
29771
29822
|
callbacks: {
|
|
29772
|
-
|
|
29773
|
-
const [lastValue, currentValue] = tooltipItem.raw;
|
|
29774
|
-
const yLabel = currentValue - lastValue;
|
|
29823
|
+
beforeLabel: function (tooltipItem) {
|
|
29775
29824
|
const dataSeriesIndex = labels.length
|
|
29776
29825
|
? Math.floor(tooltipItem.dataIndex / labels.length)
|
|
29777
29826
|
: 0;
|
|
29778
|
-
|
|
29827
|
+
return dataSeriesLabels[dataSeriesIndex];
|
|
29828
|
+
},
|
|
29829
|
+
label: function (tooltipItem) {
|
|
29830
|
+
const [lastValue, currentValue] = tooltipItem.raw;
|
|
29831
|
+
const yLabel = currentValue - lastValue;
|
|
29779
29832
|
const toolTipFormat = !format && Math.abs(yLabel) > 1000 ? "#,##" : format;
|
|
29780
|
-
|
|
29781
|
-
return dataSeriesLabel ? `${dataSeriesLabel}: ${yLabelStr}` : yLabelStr;
|
|
29833
|
+
return formatValue(yLabel, { format: toolTipFormat, locale });
|
|
29782
29834
|
},
|
|
29783
29835
|
},
|
|
29784
29836
|
};
|
|
@@ -29802,11 +29854,10 @@ function getRadarChartTooltip(definition, args) {
|
|
|
29802
29854
|
enabled: false,
|
|
29803
29855
|
external: customTooltipHandler,
|
|
29804
29856
|
callbacks: {
|
|
29857
|
+
beforeLabel: (tooltipItem) => tooltipItem.dataset?.label || tooltipItem.label,
|
|
29805
29858
|
label: function (tooltipItem) {
|
|
29806
|
-
const xLabel = tooltipItem.dataset?.label || tooltipItem.label;
|
|
29807
29859
|
const yLabel = tooltipItem.parsed.r;
|
|
29808
|
-
|
|
29809
|
-
return xLabel ? `${xLabel}: ${formattedY}` : formattedY;
|
|
29860
|
+
return formatValue(yLabel, { format: axisFormats?.r, locale });
|
|
29810
29861
|
},
|
|
29811
29862
|
},
|
|
29812
29863
|
};
|
|
@@ -29821,13 +29872,12 @@ function getGeoChartTooltip(definition, args) {
|
|
|
29821
29872
|
return tooltipItem.raw.value !== undefined;
|
|
29822
29873
|
},
|
|
29823
29874
|
callbacks: {
|
|
29875
|
+
beforeLabel: (tooltipItem) => tooltipItem.raw.feature.properties.name,
|
|
29824
29876
|
label: function (tooltipItem) {
|
|
29825
29877
|
const rawItem = tooltipItem.raw;
|
|
29826
|
-
const xLabel = rawItem.feature.properties.name;
|
|
29827
29878
|
const yLabel = rawItem.value;
|
|
29828
29879
|
const toolTipFormat = !format && Math.abs(yLabel) >= 1000 ? "#,##" : format;
|
|
29829
|
-
|
|
29830
|
-
return xLabel ? `${xLabel}: ${yLabelStr}` : yLabelStr;
|
|
29880
|
+
return formatValue(yLabel, { format: toolTipFormat, locale });
|
|
29831
29881
|
},
|
|
29832
29882
|
},
|
|
29833
29883
|
};
|
|
@@ -29847,7 +29897,8 @@ function customTooltipHandler({ chart, tooltip }) {
|
|
|
29847
29897
|
return;
|
|
29848
29898
|
}
|
|
29849
29899
|
const tooltipItems = tooltip.body.map((body, index) => {
|
|
29850
|
-
let
|
|
29900
|
+
let label = body.before[0];
|
|
29901
|
+
let value = body.lines[0];
|
|
29851
29902
|
if (!value) {
|
|
29852
29903
|
value = label;
|
|
29853
29904
|
label = "";
|
|
@@ -33008,6 +33059,187 @@ const FilterMenuPopoverBuilder = {
|
|
|
33008
33059
|
},
|
|
33009
33060
|
};
|
|
33010
33061
|
|
|
33062
|
+
const macRegex = /Mac/i;
|
|
33063
|
+
const MODIFIER_KEYS = ["Shift", "Control", "Alt", "Meta"];
|
|
33064
|
+
/**
|
|
33065
|
+
* Return true if the event was triggered from
|
|
33066
|
+
* a child element.
|
|
33067
|
+
*/
|
|
33068
|
+
function isChildEvent(parent, ev) {
|
|
33069
|
+
if (!parent)
|
|
33070
|
+
return false;
|
|
33071
|
+
return !!ev.target && parent.contains(ev.target);
|
|
33072
|
+
}
|
|
33073
|
+
function gridOverlayPosition() {
|
|
33074
|
+
const spreadsheetElement = document.querySelector(".o-grid-overlay");
|
|
33075
|
+
if (spreadsheetElement) {
|
|
33076
|
+
const { top, left } = spreadsheetElement?.getBoundingClientRect();
|
|
33077
|
+
return { top, left };
|
|
33078
|
+
}
|
|
33079
|
+
throw new Error("Can't find spreadsheet position");
|
|
33080
|
+
}
|
|
33081
|
+
function getBoundingRectAsPOJO(el) {
|
|
33082
|
+
const rect = el.getBoundingClientRect();
|
|
33083
|
+
return {
|
|
33084
|
+
x: rect.x,
|
|
33085
|
+
y: rect.y,
|
|
33086
|
+
width: rect.width,
|
|
33087
|
+
height: rect.height,
|
|
33088
|
+
};
|
|
33089
|
+
}
|
|
33090
|
+
/**
|
|
33091
|
+
* Iterate over all the children of `el` in the dom tree starting at `el`, depth first.
|
|
33092
|
+
*/
|
|
33093
|
+
function* iterateChildren(el) {
|
|
33094
|
+
yield el;
|
|
33095
|
+
if (el.hasChildNodes()) {
|
|
33096
|
+
for (let child of el.childNodes) {
|
|
33097
|
+
yield* iterateChildren(child);
|
|
33098
|
+
}
|
|
33099
|
+
}
|
|
33100
|
+
}
|
|
33101
|
+
function getOpenedMenus() {
|
|
33102
|
+
return Array.from(document.querySelectorAll(".o-spreadsheet .o-menu"));
|
|
33103
|
+
}
|
|
33104
|
+
function getCurrentSelection(el) {
|
|
33105
|
+
let { startElement, endElement, startSelectionOffset, endSelectionOffset } = getStartAndEndSelection(el);
|
|
33106
|
+
let startSizeBefore = findSelectionIndex(el, startElement, startSelectionOffset);
|
|
33107
|
+
let endSizeBefore = findSelectionIndex(el, endElement, endSelectionOffset);
|
|
33108
|
+
return {
|
|
33109
|
+
start: startSizeBefore,
|
|
33110
|
+
end: endSizeBefore,
|
|
33111
|
+
};
|
|
33112
|
+
}
|
|
33113
|
+
function getStartAndEndSelection(el) {
|
|
33114
|
+
const selection = document.getSelection();
|
|
33115
|
+
return {
|
|
33116
|
+
startElement: selection.anchorNode || el,
|
|
33117
|
+
startSelectionOffset: selection.anchorOffset,
|
|
33118
|
+
endElement: selection.focusNode || el,
|
|
33119
|
+
endSelectionOffset: selection.focusOffset,
|
|
33120
|
+
};
|
|
33121
|
+
}
|
|
33122
|
+
/**
|
|
33123
|
+
* Computes the text 'index' inside this.el based on the currently selected node and its offset.
|
|
33124
|
+
* The selected node is either a Text node or an Element node.
|
|
33125
|
+
*
|
|
33126
|
+
* case 1 -Text node:
|
|
33127
|
+
* the offset is the number of characters from the start of the node. We have to add this offset to the
|
|
33128
|
+
* content length of all previous nodes.
|
|
33129
|
+
*
|
|
33130
|
+
* case 2 - Element node:
|
|
33131
|
+
* the offset is the number of child nodes before the selected node. We have to add the content length of
|
|
33132
|
+
* all the nodes prior to the selected node as well as the content of the child node before the offset.
|
|
33133
|
+
*
|
|
33134
|
+
* See the MDN documentation for more details.
|
|
33135
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/Range/startOffset
|
|
33136
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/Range/endOffset
|
|
33137
|
+
*
|
|
33138
|
+
*/
|
|
33139
|
+
function findSelectionIndex(el, nodeToFind, nodeOffset) {
|
|
33140
|
+
let usedCharacters = 0;
|
|
33141
|
+
let it = iterateChildren(el);
|
|
33142
|
+
let current = it.next();
|
|
33143
|
+
let isFirstParagraph = true;
|
|
33144
|
+
while (!current.done && current.value !== nodeToFind) {
|
|
33145
|
+
if (!current.value.hasChildNodes()) {
|
|
33146
|
+
if (current.value.textContent) {
|
|
33147
|
+
usedCharacters += current.value.textContent.length;
|
|
33148
|
+
}
|
|
33149
|
+
}
|
|
33150
|
+
// One new paragraph = one new line character, except for the first paragraph
|
|
33151
|
+
if (current.value.nodeName === "P" ||
|
|
33152
|
+
(current.value.nodeName === "DIV" && current.value !== el) // On paste, the HTML may contain <div> instead of <p>
|
|
33153
|
+
) {
|
|
33154
|
+
if (isFirstParagraph) {
|
|
33155
|
+
isFirstParagraph = false;
|
|
33156
|
+
}
|
|
33157
|
+
else {
|
|
33158
|
+
usedCharacters++;
|
|
33159
|
+
}
|
|
33160
|
+
}
|
|
33161
|
+
current = it.next();
|
|
33162
|
+
}
|
|
33163
|
+
if (current.value !== nodeToFind) {
|
|
33164
|
+
/** This situation can happen if the code is called while the selection is not currently on the element.
|
|
33165
|
+
* In this case, we return 0 because we don't know the size of the text before the selection.
|
|
33166
|
+
*
|
|
33167
|
+
* A known occurrence is triggered since the introduction of commit d4663158 (PR #2038).
|
|
33168
|
+
*/
|
|
33169
|
+
return 0;
|
|
33170
|
+
}
|
|
33171
|
+
else {
|
|
33172
|
+
if (!current.value.hasChildNodes()) {
|
|
33173
|
+
usedCharacters += nodeOffset;
|
|
33174
|
+
}
|
|
33175
|
+
else {
|
|
33176
|
+
const children = [...current.value.childNodes].slice(0, nodeOffset);
|
|
33177
|
+
usedCharacters += children.reduce((acc, child, index) => {
|
|
33178
|
+
if (child.textContent !== null) {
|
|
33179
|
+
// need to account for paragraph nodes that implicitly add a new line
|
|
33180
|
+
// except for the last paragraph
|
|
33181
|
+
let chars = child.textContent.length;
|
|
33182
|
+
if (child.nodeName === "P" && index !== children.length - 1) {
|
|
33183
|
+
chars++;
|
|
33184
|
+
}
|
|
33185
|
+
return acc + chars;
|
|
33186
|
+
}
|
|
33187
|
+
else {
|
|
33188
|
+
return acc;
|
|
33189
|
+
}
|
|
33190
|
+
}, 0);
|
|
33191
|
+
}
|
|
33192
|
+
}
|
|
33193
|
+
if (nodeToFind.nodeName === "P" && !isFirstParagraph && nodeToFind.textContent === "") {
|
|
33194
|
+
usedCharacters++;
|
|
33195
|
+
}
|
|
33196
|
+
return usedCharacters;
|
|
33197
|
+
}
|
|
33198
|
+
const letterRegex = /^[a-zA-Z]$/;
|
|
33199
|
+
/**
|
|
33200
|
+
* Transform a keyboard event into a shortcut string that represent this event. The letters keys will be uppercased.
|
|
33201
|
+
*
|
|
33202
|
+
* @argument ev - The keyboard event to transform
|
|
33203
|
+
* @argument mode - Use either ev.key of ev.code to get the string shortcut
|
|
33204
|
+
*
|
|
33205
|
+
* @example
|
|
33206
|
+
* event : { ctrlKey: true, key: "a" } => "Ctrl+A"
|
|
33207
|
+
* event : { shift: true, alt: true, key: "Home" } => "Alt+Shift+Home"
|
|
33208
|
+
*/
|
|
33209
|
+
function keyboardEventToShortcutString(ev, mode = "key") {
|
|
33210
|
+
let keyDownString = "";
|
|
33211
|
+
if (!MODIFIER_KEYS.includes(ev.key)) {
|
|
33212
|
+
if (isCtrlKey(ev))
|
|
33213
|
+
keyDownString += "Ctrl+";
|
|
33214
|
+
if (ev.altKey)
|
|
33215
|
+
keyDownString += "Alt+";
|
|
33216
|
+
if (ev.shiftKey)
|
|
33217
|
+
keyDownString += "Shift+";
|
|
33218
|
+
}
|
|
33219
|
+
const key = mode === "key" ? ev.key : ev.code;
|
|
33220
|
+
keyDownString += letterRegex.test(key) ? key.toUpperCase() : key;
|
|
33221
|
+
return keyDownString;
|
|
33222
|
+
}
|
|
33223
|
+
function isMacOS() {
|
|
33224
|
+
return Boolean(macRegex.test(navigator.userAgent));
|
|
33225
|
+
}
|
|
33226
|
+
/**
|
|
33227
|
+
* @param {KeyboardEvent | MouseEvent} ev
|
|
33228
|
+
* @returns Returns true if the event was triggered with the "ctrl" modifier pressed.
|
|
33229
|
+
* On Mac, this is the "meta" or "command" key.
|
|
33230
|
+
*/
|
|
33231
|
+
function isCtrlKey(ev) {
|
|
33232
|
+
return isMacOS() ? ev.metaKey : ev.ctrlKey;
|
|
33233
|
+
}
|
|
33234
|
+
/**
|
|
33235
|
+
* @param {MouseEvent} ev - The mouse event.
|
|
33236
|
+
* @returns {boolean} Returns true if the event was triggered by a middle-click
|
|
33237
|
+
* or a Ctrl + Click (Cmd + Click on Mac).
|
|
33238
|
+
*/
|
|
33239
|
+
function isMiddleClickOrCtrlClick(ev) {
|
|
33240
|
+
return ev.button === 1 || (isCtrlKey(ev) && ev.button === 0);
|
|
33241
|
+
}
|
|
33242
|
+
|
|
33011
33243
|
const LINK_TOOLTIP_HEIGHT = 32;
|
|
33012
33244
|
const LINK_TOOLTIP_WIDTH = 220;
|
|
33013
33245
|
css /* scss */ `
|
|
@@ -33082,8 +33314,8 @@ class LinkDisplay extends owl.Component {
|
|
|
33082
33314
|
getUrlRepresentation(link) {
|
|
33083
33315
|
return urlRepresentation(link, this.env.model.getters);
|
|
33084
33316
|
}
|
|
33085
|
-
openLink() {
|
|
33086
|
-
openLink(this.link, this.env);
|
|
33317
|
+
openLink(ev) {
|
|
33318
|
+
openLink(this.link, this.env, isMiddleClickOrCtrlClick(ev));
|
|
33087
33319
|
}
|
|
33088
33320
|
edit() {
|
|
33089
33321
|
const { col, row } = this.props.cellPosition;
|
|
@@ -33212,179 +33444,6 @@ linkMenuRegistry.add("sheet", {
|
|
|
33212
33444
|
sequence: 10,
|
|
33213
33445
|
});
|
|
33214
33446
|
|
|
33215
|
-
const macRegex = /Mac/i;
|
|
33216
|
-
const MODIFIER_KEYS = ["Shift", "Control", "Alt", "Meta"];
|
|
33217
|
-
/**
|
|
33218
|
-
* Return true if the event was triggered from
|
|
33219
|
-
* a child element.
|
|
33220
|
-
*/
|
|
33221
|
-
function isChildEvent(parent, ev) {
|
|
33222
|
-
if (!parent)
|
|
33223
|
-
return false;
|
|
33224
|
-
return !!ev.target && parent.contains(ev.target);
|
|
33225
|
-
}
|
|
33226
|
-
function gridOverlayPosition() {
|
|
33227
|
-
const spreadsheetElement = document.querySelector(".o-grid-overlay");
|
|
33228
|
-
if (spreadsheetElement) {
|
|
33229
|
-
const { top, left } = spreadsheetElement?.getBoundingClientRect();
|
|
33230
|
-
return { top, left };
|
|
33231
|
-
}
|
|
33232
|
-
throw new Error("Can't find spreadsheet position");
|
|
33233
|
-
}
|
|
33234
|
-
function getBoundingRectAsPOJO(el) {
|
|
33235
|
-
const rect = el.getBoundingClientRect();
|
|
33236
|
-
return {
|
|
33237
|
-
x: rect.x,
|
|
33238
|
-
y: rect.y,
|
|
33239
|
-
width: rect.width,
|
|
33240
|
-
height: rect.height,
|
|
33241
|
-
};
|
|
33242
|
-
}
|
|
33243
|
-
/**
|
|
33244
|
-
* Iterate over all the children of `el` in the dom tree starting at `el`, depth first.
|
|
33245
|
-
*/
|
|
33246
|
-
function* iterateChildren(el) {
|
|
33247
|
-
yield el;
|
|
33248
|
-
if (el.hasChildNodes()) {
|
|
33249
|
-
for (let child of el.childNodes) {
|
|
33250
|
-
yield* iterateChildren(child);
|
|
33251
|
-
}
|
|
33252
|
-
}
|
|
33253
|
-
}
|
|
33254
|
-
function getOpenedMenus() {
|
|
33255
|
-
return Array.from(document.querySelectorAll(".o-spreadsheet .o-menu"));
|
|
33256
|
-
}
|
|
33257
|
-
function getCurrentSelection(el) {
|
|
33258
|
-
let { startElement, endElement, startSelectionOffset, endSelectionOffset } = getStartAndEndSelection(el);
|
|
33259
|
-
let startSizeBefore = findSelectionIndex(el, startElement, startSelectionOffset);
|
|
33260
|
-
let endSizeBefore = findSelectionIndex(el, endElement, endSelectionOffset);
|
|
33261
|
-
return {
|
|
33262
|
-
start: startSizeBefore,
|
|
33263
|
-
end: endSizeBefore,
|
|
33264
|
-
};
|
|
33265
|
-
}
|
|
33266
|
-
function getStartAndEndSelection(el) {
|
|
33267
|
-
const selection = document.getSelection();
|
|
33268
|
-
return {
|
|
33269
|
-
startElement: selection.anchorNode || el,
|
|
33270
|
-
startSelectionOffset: selection.anchorOffset,
|
|
33271
|
-
endElement: selection.focusNode || el,
|
|
33272
|
-
endSelectionOffset: selection.focusOffset,
|
|
33273
|
-
};
|
|
33274
|
-
}
|
|
33275
|
-
/**
|
|
33276
|
-
* Computes the text 'index' inside this.el based on the currently selected node and its offset.
|
|
33277
|
-
* The selected node is either a Text node or an Element node.
|
|
33278
|
-
*
|
|
33279
|
-
* case 1 -Text node:
|
|
33280
|
-
* the offset is the number of characters from the start of the node. We have to add this offset to the
|
|
33281
|
-
* content length of all previous nodes.
|
|
33282
|
-
*
|
|
33283
|
-
* case 2 - Element node:
|
|
33284
|
-
* the offset is the number of child nodes before the selected node. We have to add the content length of
|
|
33285
|
-
* all the nodes prior to the selected node as well as the content of the child node before the offset.
|
|
33286
|
-
*
|
|
33287
|
-
* See the MDN documentation for more details.
|
|
33288
|
-
* https://developer.mozilla.org/en-US/docs/Web/API/Range/startOffset
|
|
33289
|
-
* https://developer.mozilla.org/en-US/docs/Web/API/Range/endOffset
|
|
33290
|
-
*
|
|
33291
|
-
*/
|
|
33292
|
-
function findSelectionIndex(el, nodeToFind, nodeOffset) {
|
|
33293
|
-
let usedCharacters = 0;
|
|
33294
|
-
let it = iterateChildren(el);
|
|
33295
|
-
let current = it.next();
|
|
33296
|
-
let isFirstParagraph = true;
|
|
33297
|
-
while (!current.done && current.value !== nodeToFind) {
|
|
33298
|
-
if (!current.value.hasChildNodes()) {
|
|
33299
|
-
if (current.value.textContent) {
|
|
33300
|
-
usedCharacters += current.value.textContent.length;
|
|
33301
|
-
}
|
|
33302
|
-
}
|
|
33303
|
-
// One new paragraph = one new line character, except for the first paragraph
|
|
33304
|
-
if (current.value.nodeName === "P" ||
|
|
33305
|
-
(current.value.nodeName === "DIV" && current.value !== el) // On paste, the HTML may contain <div> instead of <p>
|
|
33306
|
-
) {
|
|
33307
|
-
if (isFirstParagraph) {
|
|
33308
|
-
isFirstParagraph = false;
|
|
33309
|
-
}
|
|
33310
|
-
else {
|
|
33311
|
-
usedCharacters++;
|
|
33312
|
-
}
|
|
33313
|
-
}
|
|
33314
|
-
current = it.next();
|
|
33315
|
-
}
|
|
33316
|
-
if (current.value !== nodeToFind) {
|
|
33317
|
-
/** This situation can happen if the code is called while the selection is not currently on the element.
|
|
33318
|
-
* In this case, we return 0 because we don't know the size of the text before the selection.
|
|
33319
|
-
*
|
|
33320
|
-
* A known occurrence is triggered since the introduction of commit d4663158 (PR #2038).
|
|
33321
|
-
*/
|
|
33322
|
-
return 0;
|
|
33323
|
-
}
|
|
33324
|
-
else {
|
|
33325
|
-
if (!current.value.hasChildNodes()) {
|
|
33326
|
-
usedCharacters += nodeOffset;
|
|
33327
|
-
}
|
|
33328
|
-
else {
|
|
33329
|
-
const children = [...current.value.childNodes].slice(0, nodeOffset);
|
|
33330
|
-
usedCharacters += children.reduce((acc, child, index) => {
|
|
33331
|
-
if (child.textContent !== null) {
|
|
33332
|
-
// need to account for paragraph nodes that implicitly add a new line
|
|
33333
|
-
// except for the last paragraph
|
|
33334
|
-
let chars = child.textContent.length;
|
|
33335
|
-
if (child.nodeName === "P" && index !== children.length - 1) {
|
|
33336
|
-
chars++;
|
|
33337
|
-
}
|
|
33338
|
-
return acc + chars;
|
|
33339
|
-
}
|
|
33340
|
-
else {
|
|
33341
|
-
return acc;
|
|
33342
|
-
}
|
|
33343
|
-
}, 0);
|
|
33344
|
-
}
|
|
33345
|
-
}
|
|
33346
|
-
if (nodeToFind.nodeName === "P" && !isFirstParagraph && nodeToFind.textContent === "") {
|
|
33347
|
-
usedCharacters++;
|
|
33348
|
-
}
|
|
33349
|
-
return usedCharacters;
|
|
33350
|
-
}
|
|
33351
|
-
const letterRegex = /^[a-zA-Z]$/;
|
|
33352
|
-
/**
|
|
33353
|
-
* Transform a keyboard event into a shortcut string that represent this event. The letters keys will be uppercased.
|
|
33354
|
-
*
|
|
33355
|
-
* @argument ev - The keyboard event to transform
|
|
33356
|
-
* @argument mode - Use either ev.key of ev.code to get the string shortcut
|
|
33357
|
-
*
|
|
33358
|
-
* @example
|
|
33359
|
-
* event : { ctrlKey: true, key: "a" } => "Ctrl+A"
|
|
33360
|
-
* event : { shift: true, alt: true, key: "Home" } => "Alt+Shift+Home"
|
|
33361
|
-
*/
|
|
33362
|
-
function keyboardEventToShortcutString(ev, mode = "key") {
|
|
33363
|
-
let keyDownString = "";
|
|
33364
|
-
if (!MODIFIER_KEYS.includes(ev.key)) {
|
|
33365
|
-
if (isCtrlKey(ev))
|
|
33366
|
-
keyDownString += "Ctrl+";
|
|
33367
|
-
if (ev.altKey)
|
|
33368
|
-
keyDownString += "Alt+";
|
|
33369
|
-
if (ev.shiftKey)
|
|
33370
|
-
keyDownString += "Shift+";
|
|
33371
|
-
}
|
|
33372
|
-
const key = mode === "key" ? ev.key : ev.code;
|
|
33373
|
-
keyDownString += letterRegex.test(key) ? key.toUpperCase() : key;
|
|
33374
|
-
return keyDownString;
|
|
33375
|
-
}
|
|
33376
|
-
function isMacOS() {
|
|
33377
|
-
return Boolean(macRegex.test(navigator.userAgent));
|
|
33378
|
-
}
|
|
33379
|
-
/**
|
|
33380
|
-
* @param {KeyboardEvent | MouseEvent} ev
|
|
33381
|
-
* @returns Returns true if the event was triggered with the "ctrl" modifier pressed.
|
|
33382
|
-
* On Mac, this is the "meta" or "command" key.
|
|
33383
|
-
*/
|
|
33384
|
-
function isCtrlKey(ev) {
|
|
33385
|
-
return isMacOS() ? ev.metaKey : ev.ctrlKey;
|
|
33386
|
-
}
|
|
33387
|
-
|
|
33388
33447
|
/**
|
|
33389
33448
|
* Repeatedly calls a callback function with a time delay between calls.
|
|
33390
33449
|
*/
|
|
@@ -33579,8 +33638,8 @@ class Menu extends owl.Component {
|
|
|
33579
33638
|
getIconColor(menu) {
|
|
33580
33639
|
return cssPropertiesToCss({ color: menu.iconColor });
|
|
33581
33640
|
}
|
|
33582
|
-
async activateMenu(menu) {
|
|
33583
|
-
const result = await menu.execute?.(this.env);
|
|
33641
|
+
async activateMenu(menu, isMiddleClick) {
|
|
33642
|
+
const result = await menu.execute?.(this.env, isMiddleClick);
|
|
33584
33643
|
this.close();
|
|
33585
33644
|
this.props.onMenuClicked?.({ detail: result });
|
|
33586
33645
|
}
|
|
@@ -33643,13 +33702,14 @@ class Menu extends owl.Component {
|
|
|
33643
33702
|
this.subMenu.parentMenu = undefined;
|
|
33644
33703
|
}
|
|
33645
33704
|
onClickMenu(menu, ev) {
|
|
33646
|
-
if (this.isEnabled(menu)) {
|
|
33647
|
-
|
|
33648
|
-
|
|
33649
|
-
|
|
33650
|
-
|
|
33651
|
-
|
|
33652
|
-
|
|
33705
|
+
if (!this.isEnabled(menu)) {
|
|
33706
|
+
return;
|
|
33707
|
+
}
|
|
33708
|
+
if (this.isRoot(menu)) {
|
|
33709
|
+
this.openSubMenu(menu, ev.currentTarget);
|
|
33710
|
+
}
|
|
33711
|
+
else {
|
|
33712
|
+
this.activateMenu(menu, isMiddleClickOrCtrlClick(ev));
|
|
33653
33713
|
}
|
|
33654
33714
|
}
|
|
33655
33715
|
onMouseOver(menu, ev) {
|
|
@@ -40277,7 +40337,7 @@ class Composer extends owl.Component {
|
|
|
40277
40337
|
const content = this.props.composerStore.currentContent;
|
|
40278
40338
|
if (this.props.focus === "cellFocus" &&
|
|
40279
40339
|
!this.autoCompleteState.provider &&
|
|
40280
|
-
!content
|
|
40340
|
+
!isFormula(content)) {
|
|
40281
40341
|
this.props.composerStore.stopEdition();
|
|
40282
40342
|
return;
|
|
40283
40343
|
}
|
|
@@ -40494,7 +40554,7 @@ class Composer extends owl.Component {
|
|
|
40494
40554
|
return;
|
|
40495
40555
|
}
|
|
40496
40556
|
const composerContent = this.props.composerStore.currentContent;
|
|
40497
|
-
const isValidFormula = composerContent
|
|
40557
|
+
const isValidFormula = isFormula(composerContent);
|
|
40498
40558
|
if (isValidFormula) {
|
|
40499
40559
|
const tokens = this.props.composerStore.currentTokens;
|
|
40500
40560
|
const currentSelection = this.contentHelper.getCurrentSelection();
|
|
@@ -40551,7 +40611,7 @@ class Composer extends owl.Component {
|
|
|
40551
40611
|
*/
|
|
40552
40612
|
getContentLines() {
|
|
40553
40613
|
let value = this.props.composerStore.currentContent;
|
|
40554
|
-
const isValidFormula = value
|
|
40614
|
+
const isValidFormula = isFormula(value);
|
|
40555
40615
|
if (value === "") {
|
|
40556
40616
|
return [];
|
|
40557
40617
|
}
|
|
@@ -40640,7 +40700,7 @@ class Composer extends owl.Component {
|
|
|
40640
40700
|
this.autoCompleteState.useProvider(autoCompleteProvider);
|
|
40641
40701
|
}
|
|
40642
40702
|
const token = this.props.composerStore.tokenAtCursor;
|
|
40643
|
-
if (content
|
|
40703
|
+
if (isFormula(content) && token && token.type !== "SYMBOL") {
|
|
40644
40704
|
const tokenContext = token.functionContext;
|
|
40645
40705
|
const parentFunction = tokenContext?.parent.toUpperCase();
|
|
40646
40706
|
if (tokenContext &&
|
|
@@ -48698,7 +48758,7 @@ class CellComposerStore extends AbstractComposerStore {
|
|
|
48698
48758
|
}
|
|
48699
48759
|
break;
|
|
48700
48760
|
case "ACTIVATE_SHEET":
|
|
48701
|
-
if (!this._currentContent
|
|
48761
|
+
if (!isFormula(this._currentContent)) {
|
|
48702
48762
|
this._cancelEdition();
|
|
48703
48763
|
this.resetContent();
|
|
48704
48764
|
}
|
|
@@ -48774,7 +48834,7 @@ class CellComposerStore extends AbstractComposerStore {
|
|
|
48774
48834
|
if (content) {
|
|
48775
48835
|
const sheetId = this.getters.getActiveSheetId();
|
|
48776
48836
|
const cell = this.getters.getEvaluatedCell({ sheetId, col: this.col, row: this.row });
|
|
48777
|
-
if (cell.link && !content
|
|
48837
|
+
if (cell.link && !isFormula(content)) {
|
|
48778
48838
|
content = markdownLink(content, cell.link.url);
|
|
48779
48839
|
}
|
|
48780
48840
|
this.addHeadersForSpreadingFormula(content);
|
|
@@ -48834,7 +48894,7 @@ class CellComposerStore extends AbstractComposerStore {
|
|
|
48834
48894
|
}
|
|
48835
48895
|
/** Add headers at the end of the sheet so the formula in the composer has enough space to spread */
|
|
48836
48896
|
addHeadersForSpreadingFormula(content) {
|
|
48837
|
-
if (!content
|
|
48897
|
+
if (!isFormula(content)) {
|
|
48838
48898
|
return;
|
|
48839
48899
|
}
|
|
48840
48900
|
const evaluated = this.getters.evaluateFormula(this.sheetId, content);
|
|
@@ -48867,7 +48927,7 @@ class CellComposerStore extends AbstractComposerStore {
|
|
|
48867
48927
|
checkDataValidation() {
|
|
48868
48928
|
const cellPosition = { sheetId: this.sheetId, col: this.col, row: this.row };
|
|
48869
48929
|
const content = this.getCurrentCanonicalContent();
|
|
48870
|
-
const cellValue = content
|
|
48930
|
+
const cellValue = isFormula(content)
|
|
48871
48931
|
? this.getters.evaluateFormula(this.sheetId, content)
|
|
48872
48932
|
: parseLiteral(content, this.getters.getLocale());
|
|
48873
48933
|
if (isMatrix(cellValue)) {
|
|
@@ -48989,23 +49049,23 @@ class GridComposer extends owl.Component {
|
|
|
48989
49049
|
if (this.composerStore.editionMode === "inactive") {
|
|
48990
49050
|
return `z-index: -1000;`;
|
|
48991
49051
|
}
|
|
48992
|
-
const
|
|
49052
|
+
const _isFormula = isFormula(this.composerStore.currentContent);
|
|
48993
49053
|
const cell = this.env.model.getters.getActiveCell();
|
|
48994
49054
|
const position = this.env.model.getters.getActivePosition();
|
|
48995
49055
|
const style = this.env.model.getters.getCellComputedStyle(position);
|
|
48996
49056
|
// position style
|
|
48997
49057
|
const { x: left, y: top, width, height } = this.rect;
|
|
48998
49058
|
// color style
|
|
48999
|
-
const background = (!
|
|
49000
|
-
const color = (!
|
|
49059
|
+
const background = (!_isFormula && style.fillColor) || "#ffffff";
|
|
49060
|
+
const color = (!_isFormula && style.textColor) || "#000000";
|
|
49001
49061
|
// font style
|
|
49002
|
-
const fontSize = (!
|
|
49003
|
-
const fontWeight = !
|
|
49004
|
-
const fontStyle = !
|
|
49005
|
-
const textDecoration = !
|
|
49062
|
+
const fontSize = (!_isFormula && style.fontSize) || 10;
|
|
49063
|
+
const fontWeight = !_isFormula && style.bold ? "bold" : undefined;
|
|
49064
|
+
const fontStyle = !_isFormula && style.italic ? "italic" : "normal";
|
|
49065
|
+
const textDecoration = !_isFormula ? getTextDecoration(style) : "none";
|
|
49006
49066
|
// align style
|
|
49007
49067
|
let textAlign = "left";
|
|
49008
|
-
if (!
|
|
49068
|
+
if (!_isFormula) {
|
|
49009
49069
|
textAlign = style.align || cell.defaultAlign;
|
|
49010
49070
|
}
|
|
49011
49071
|
const maxHeight = this.props.gridDims.height - this.rect.y;
|
|
@@ -51639,8 +51699,8 @@ class Border extends owl.Component {
|
|
|
51639
51699
|
css /* scss */ `
|
|
51640
51700
|
.o-corner {
|
|
51641
51701
|
position: absolute;
|
|
51642
|
-
height:
|
|
51643
|
-
width:
|
|
51702
|
+
height: 8px;
|
|
51703
|
+
width: 8px;
|
|
51644
51704
|
border: 1px solid white;
|
|
51645
51705
|
}
|
|
51646
51706
|
.o-corner-nw,
|
|
@@ -53205,7 +53265,7 @@ class BordersPlugin extends CorePlugin {
|
|
|
53205
53265
|
this.history.update("borders", sheetId, col, row, "left", border?.left);
|
|
53206
53266
|
if (border?.left &&
|
|
53207
53267
|
col > 0 &&
|
|
53208
|
-
!deepEquals(this.
|
|
53268
|
+
!deepEquals(this.borders[sheetId]?.[col - 1]?.[row]?.right, border?.left)) {
|
|
53209
53269
|
this.history.update("borders", sheetId, col - 1, row, "right", undefined);
|
|
53210
53270
|
}
|
|
53211
53271
|
}
|
|
@@ -53213,7 +53273,7 @@ class BordersPlugin extends CorePlugin {
|
|
|
53213
53273
|
this.history.update("borders", sheetId, col, row, "top", border?.top);
|
|
53214
53274
|
if (border?.top &&
|
|
53215
53275
|
row > 0 &&
|
|
53216
|
-
!deepEquals(this.
|
|
53276
|
+
!deepEquals(this.borders[sheetId]?.[col]?.[row - 1]?.bottom, border?.top)) {
|
|
53217
53277
|
this.history.update("borders", sheetId, col, row - 1, "bottom", undefined);
|
|
53218
53278
|
}
|
|
53219
53279
|
}
|
|
@@ -53221,7 +53281,7 @@ class BordersPlugin extends CorePlugin {
|
|
|
53221
53281
|
this.history.update("borders", sheetId, col, row, "right", border?.right);
|
|
53222
53282
|
if (border?.right &&
|
|
53223
53283
|
col < maxCol &&
|
|
53224
|
-
!deepEquals(this.
|
|
53284
|
+
!deepEquals(this.borders[sheetId]?.[col + 1]?.[row]?.left, border?.right)) {
|
|
53225
53285
|
this.history.update("borders", sheetId, col + 1, row, "left", undefined);
|
|
53226
53286
|
}
|
|
53227
53287
|
}
|
|
@@ -53229,7 +53289,7 @@ class BordersPlugin extends CorePlugin {
|
|
|
53229
53289
|
this.history.update("borders", sheetId, col, row, "bottom", border?.bottom);
|
|
53230
53290
|
if (border?.bottom &&
|
|
53231
53291
|
row < maxRow &&
|
|
53232
|
-
!deepEquals(this.
|
|
53292
|
+
!deepEquals(this.borders[sheetId]?.[col]?.[row + 1]?.top, border?.bottom)) {
|
|
53233
53293
|
this.history.update("borders", sheetId, col, row + 1, "top", undefined);
|
|
53234
53294
|
}
|
|
53235
53295
|
}
|
|
@@ -60001,6 +60061,10 @@ class Evaluator {
|
|
|
60001
60061
|
this.compilationParams = buildCompilationParameters(this.context, this.getters, this.computeAndSave.bind(this));
|
|
60002
60062
|
this.compilationParams.evalContext.updateDependencies = this.updateDependencies.bind(this);
|
|
60003
60063
|
this.compilationParams.evalContext.addDependencies = this.addDependencies.bind(this);
|
|
60064
|
+
this.compilationParams.evalContext.lookupCaches = {
|
|
60065
|
+
forwardSearch: new Map(),
|
|
60066
|
+
reverseSearch: new Map(),
|
|
60067
|
+
};
|
|
60004
60068
|
}
|
|
60005
60069
|
createEmptyPositionSet() {
|
|
60006
60070
|
const sheetSizes = {};
|
|
@@ -68617,7 +68681,7 @@ clickableCellRegistry.add("link", {
|
|
|
68617
68681
|
condition: (position, getters) => {
|
|
68618
68682
|
return !!getters.getEvaluatedCell(position).link;
|
|
68619
68683
|
},
|
|
68620
|
-
execute: (position, env) => openLink(env.model.getters.getEvaluatedCell(position).link, env),
|
|
68684
|
+
execute: (position, env, isMiddleClick) => openLink(env.model.getters.getEvaluatedCell(position).link, env, isMiddleClick),
|
|
68621
68685
|
sequence: 5,
|
|
68622
68686
|
});
|
|
68623
68687
|
|
|
@@ -69602,9 +69666,9 @@ class SpreadsheetDashboard extends owl.Component {
|
|
|
69602
69666
|
getClickableCells() {
|
|
69603
69667
|
return owl.toRaw(this.clickableCellsStore.clickableCells);
|
|
69604
69668
|
}
|
|
69605
|
-
selectClickableCell(clickableCell) {
|
|
69669
|
+
selectClickableCell(ev, clickableCell) {
|
|
69606
69670
|
const { position, action } = clickableCell;
|
|
69607
|
-
action(position, this.env);
|
|
69671
|
+
action(position, this.env, isMiddleClickOrCtrlClick(ev));
|
|
69608
69672
|
}
|
|
69609
69673
|
onClosePopover() {
|
|
69610
69674
|
this.cellPopovers.close();
|
|
@@ -75611,6 +75675,6 @@ exports.tokenColors = tokenColors;
|
|
|
75611
75675
|
exports.tokenize = tokenize;
|
|
75612
75676
|
|
|
75613
75677
|
|
|
75614
|
-
__info__.version = "18.
|
|
75615
|
-
__info__.date = "2025-02-
|
|
75616
|
-
__info__.hash = "
|
|
75678
|
+
__info__.version = "18.3.0-alpha.1";
|
|
75679
|
+
__info__.date = "2025-02-25T06:00:14.885Z";
|
|
75680
|
+
__info__.hash = "be4d957";
|