@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
|
import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, App, blockDom, useState, onPatched, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
|
|
@@ -992,6 +992,9 @@ function getUniqueText(text, texts, options = {}) {
|
|
|
992
992
|
}
|
|
993
993
|
return newText;
|
|
994
994
|
}
|
|
995
|
+
function isFormula(content) {
|
|
996
|
+
return content.startsWith("=") || content.startsWith("+");
|
|
997
|
+
}
|
|
995
998
|
|
|
996
999
|
const RBA_REGEX = /rgba?\(|\s+|\)/gi;
|
|
997
1000
|
const HEX_MATCH = /^#([A-F\d]{2}){3,4}$/;
|
|
@@ -4458,7 +4461,7 @@ function dichotomicSearch(data, target, mode, sortOrder, rangeLength, getValueIn
|
|
|
4458
4461
|
* @param reverseSearch if true, search in the array starting from the end.
|
|
4459
4462
|
|
|
4460
4463
|
*/
|
|
4461
|
-
function linearSearch(data, target, mode, numberOfValues, getValueInData, reverseSearch = false) {
|
|
4464
|
+
function linearSearch(data, target, mode, numberOfValues, getValueInData, lookupCaches, reverseSearch = false) {
|
|
4462
4465
|
if (target === undefined || target.value === null) {
|
|
4463
4466
|
return -1;
|
|
4464
4467
|
}
|
|
@@ -4467,17 +4470,48 @@ function linearSearch(data, target, mode, numberOfValues, getValueInData, revers
|
|
|
4467
4470
|
}
|
|
4468
4471
|
const _target = normalizeValue(target.value);
|
|
4469
4472
|
const getValue = reverseSearch
|
|
4470
|
-
? (data, i) => getValueInData(data, numberOfValues - i - 1)
|
|
4471
|
-
: getValueInData;
|
|
4473
|
+
? (data, i) => normalizeValue(getValueInData(data, numberOfValues - i - 1))
|
|
4474
|
+
: (data, i) => normalizeValue(getValueInData(data, i));
|
|
4475
|
+
// first check if the target is in the cache
|
|
4476
|
+
const isNotWildcardTarget = mode !== "wildcard" ||
|
|
4477
|
+
typeof _target !== "string" ||
|
|
4478
|
+
!(_target.includes("*") || _target.includes("?"));
|
|
4479
|
+
if (lookupCaches && isNotWildcardTarget) {
|
|
4480
|
+
const searchMode = reverseSearch ? "reverseSearch" : "forwardSearch";
|
|
4481
|
+
let cache = lookupCaches[searchMode].get(data);
|
|
4482
|
+
if (cache === undefined) {
|
|
4483
|
+
// build the cache for all the values
|
|
4484
|
+
cache = new Map();
|
|
4485
|
+
for (let i = 0; i < numberOfValues; i++) {
|
|
4486
|
+
const value = getValue(data, i) ?? null;
|
|
4487
|
+
if (!cache.has(value)) {
|
|
4488
|
+
cache.set(value, i);
|
|
4489
|
+
}
|
|
4490
|
+
}
|
|
4491
|
+
lookupCaches[searchMode].set(data, cache);
|
|
4492
|
+
}
|
|
4493
|
+
if (cache.has(_target)) {
|
|
4494
|
+
const resultIndex = cache.get(_target);
|
|
4495
|
+
return reverseSearch ? numberOfValues - resultIndex - 1 : resultIndex;
|
|
4496
|
+
}
|
|
4497
|
+
if (mode === "strict") {
|
|
4498
|
+
return -1;
|
|
4499
|
+
}
|
|
4500
|
+
}
|
|
4501
|
+
// else perform the linear search
|
|
4502
|
+
const resultIndex = _linearSearch(data, _target, mode, numberOfValues, getValue);
|
|
4503
|
+
return reverseSearch && resultIndex !== -1 ? numberOfValues - resultIndex - 1 : resultIndex;
|
|
4504
|
+
}
|
|
4505
|
+
function _linearSearch(data, _target, mode, numberOfValues, getNormalizeValue) {
|
|
4472
4506
|
let indexMatchTarget = (i) => {
|
|
4473
|
-
return
|
|
4507
|
+
return getNormalizeValue(data, i) === _target;
|
|
4474
4508
|
};
|
|
4475
4509
|
if (mode === "wildcard" &&
|
|
4476
4510
|
typeof _target === "string" &&
|
|
4477
4511
|
(_target.includes("*") || _target.includes("?"))) {
|
|
4478
4512
|
const regExp = wildcardToRegExp(_target);
|
|
4479
4513
|
indexMatchTarget = (i) => {
|
|
4480
|
-
const value =
|
|
4514
|
+
const value = getNormalizeValue(data, i);
|
|
4481
4515
|
if (typeof value === "string") {
|
|
4482
4516
|
return regExp.test(value);
|
|
4483
4517
|
}
|
|
@@ -4488,7 +4522,7 @@ function linearSearch(data, target, mode, numberOfValues, getValueInData, revers
|
|
|
4488
4522
|
let closestMatchIndex = -1;
|
|
4489
4523
|
if (mode === "nextSmaller") {
|
|
4490
4524
|
indexMatchTarget = (i) => {
|
|
4491
|
-
const value =
|
|
4525
|
+
const value = getNormalizeValue(data, i);
|
|
4492
4526
|
if ((!closestMatch && compareCellValues(_target, value) >= 0) ||
|
|
4493
4527
|
(compareCellValues(_target, value) >= 0 && compareCellValues(value, closestMatch) > 0)) {
|
|
4494
4528
|
closestMatch = value;
|
|
@@ -4499,7 +4533,7 @@ function linearSearch(data, target, mode, numberOfValues, getValueInData, revers
|
|
|
4499
4533
|
}
|
|
4500
4534
|
if (mode === "nextGreater") {
|
|
4501
4535
|
indexMatchTarget = (i) => {
|
|
4502
|
-
const value =
|
|
4536
|
+
const value = getNormalizeValue(data, i);
|
|
4503
4537
|
if ((!closestMatch && compareCellValues(_target, value) <= 0) ||
|
|
4504
4538
|
(compareCellValues(_target, value) <= 0 && compareCellValues(value, closestMatch) < 0)) {
|
|
4505
4539
|
closestMatch = value;
|
|
@@ -4510,12 +4544,10 @@ function linearSearch(data, target, mode, numberOfValues, getValueInData, revers
|
|
|
4510
4544
|
}
|
|
4511
4545
|
for (let i = 0; i < numberOfValues; i++) {
|
|
4512
4546
|
if (indexMatchTarget(i)) {
|
|
4513
|
-
return
|
|
4547
|
+
return i;
|
|
4514
4548
|
}
|
|
4515
4549
|
}
|
|
4516
|
-
return
|
|
4517
|
-
? numberOfValues - closestMatchIndex - 1
|
|
4518
|
-
: closestMatchIndex;
|
|
4550
|
+
return closestMatchIndex;
|
|
4519
4551
|
}
|
|
4520
4552
|
/**
|
|
4521
4553
|
* Normalize a value.
|
|
@@ -4631,8 +4663,8 @@ function findMatchingSpec(url) {
|
|
|
4631
4663
|
function urlRepresentation(link, getters) {
|
|
4632
4664
|
return findMatchingSpec(link.url).urlRepresentation(link.url, getters);
|
|
4633
4665
|
}
|
|
4634
|
-
function openLink(link, env) {
|
|
4635
|
-
findMatchingSpec(link.url).open(link.url, env);
|
|
4666
|
+
function openLink(link, env, isMiddleClick) {
|
|
4667
|
+
findMatchingSpec(link.url).open(link.url, env, isMiddleClick);
|
|
4636
4668
|
}
|
|
4637
4669
|
function detectLink(value) {
|
|
4638
4670
|
if (typeof value !== "string") {
|
|
@@ -6489,10 +6521,11 @@ class UuidGenerator {
|
|
|
6489
6521
|
*
|
|
6490
6522
|
*/
|
|
6491
6523
|
smallUuid() {
|
|
6492
|
-
|
|
6493
|
-
|
|
6494
|
-
|
|
6495
|
-
|
|
6524
|
+
if (window.crypto) {
|
|
6525
|
+
return "10000000-1000".replace(/[01]/g, (c) => {
|
|
6526
|
+
const n = Number(c);
|
|
6527
|
+
return (n ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (n / 4)))).toString(16);
|
|
6528
|
+
});
|
|
6496
6529
|
}
|
|
6497
6530
|
else {
|
|
6498
6531
|
// mainly for jest and other browsers that do not have the crypto functionality
|
|
@@ -6507,10 +6540,11 @@ class UuidGenerator {
|
|
|
6507
6540
|
* This method should be used when you need to avoid collisions at all costs, like the id of a revision.
|
|
6508
6541
|
*/
|
|
6509
6542
|
uuidv4() {
|
|
6510
|
-
|
|
6511
|
-
|
|
6512
|
-
|
|
6513
|
-
|
|
6543
|
+
if (window.crypto) {
|
|
6544
|
+
return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, (c) => {
|
|
6545
|
+
const n = Number(c);
|
|
6546
|
+
return (n ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (n / 4)))).toString(16);
|
|
6547
|
+
});
|
|
6514
6548
|
}
|
|
6515
6549
|
else {
|
|
6516
6550
|
// mainly for jest and other browsers that do not have the crypto functionality
|
|
@@ -6918,7 +6952,7 @@ function isValidLocale(locale) {
|
|
|
6918
6952
|
* canonicalizeNumberContent("02/12/2012", FR_LOCALE) // "02/12/2012"
|
|
6919
6953
|
*/
|
|
6920
6954
|
function canonicalizeNumberContent(content, locale) {
|
|
6921
|
-
return content
|
|
6955
|
+
return isFormula(content)
|
|
6922
6956
|
? canonicalizeFormula$1(content, locale)
|
|
6923
6957
|
: canonicalizeNumberLiteral(content, locale);
|
|
6924
6958
|
}
|
|
@@ -6933,7 +6967,7 @@ function canonicalizeNumberContent(content, locale) {
|
|
|
6933
6967
|
* canonicalizeContent("02-12-2012", FR_LOCALE) // "12/02/2012"
|
|
6934
6968
|
*/
|
|
6935
6969
|
function canonicalizeContent(content, locale) {
|
|
6936
|
-
return content
|
|
6970
|
+
return isFormula(content)
|
|
6937
6971
|
? canonicalizeFormula$1(content, locale)
|
|
6938
6972
|
: canonicalizeLiteral(content, locale);
|
|
6939
6973
|
}
|
|
@@ -6952,7 +6986,7 @@ function localizeContent(content, locale) {
|
|
|
6952
6986
|
}
|
|
6953
6987
|
/** Change a formula to its canonical form (en_US locale) */
|
|
6954
6988
|
function canonicalizeFormula$1(formula, locale) {
|
|
6955
|
-
return _localizeFormula$1(formula, locale, DEFAULT_LOCALE);
|
|
6989
|
+
return _localizeFormula$1(formula.startsWith("+") ? "=" + formula.slice(1) : formula, locale, DEFAULT_LOCALE);
|
|
6956
6990
|
}
|
|
6957
6991
|
/** Change a formula from the canonical form to the given locale */
|
|
6958
6992
|
function localizeFormula(formula, locale) {
|
|
@@ -7115,13 +7149,13 @@ function getDateTimeFormat(locale) {
|
|
|
7115
7149
|
|
|
7116
7150
|
/** Change a number string to its canonical form (en_US locale) */
|
|
7117
7151
|
function canonicalizeNumberValue(content, locale) {
|
|
7118
|
-
return content
|
|
7152
|
+
return isFormula(content)
|
|
7119
7153
|
? canonicalizeFormula(content, locale)
|
|
7120
7154
|
: canonicalizeNumberLiteral(content, locale);
|
|
7121
7155
|
}
|
|
7122
7156
|
/** Change a formula to its canonical form (en_US locale) */
|
|
7123
7157
|
function canonicalizeFormula(formula, locale) {
|
|
7124
|
-
return _localizeFormula(formula, locale, DEFAULT_LOCALE);
|
|
7158
|
+
return _localizeFormula(formula.startsWith("+") ? "=" + formula.slice(1) : formula, locale, DEFAULT_LOCALE);
|
|
7125
7159
|
}
|
|
7126
7160
|
function _localizeFormula(formula, fromLocale, toLocale) {
|
|
7127
7161
|
if (fromLocale.formulaArgSeparator === toLocale.formulaArgSeparator &&
|
|
@@ -10875,7 +10909,7 @@ const autoCompleteProviders = new Registry();
|
|
|
10875
10909
|
|
|
10876
10910
|
autoCompleteProviders.add("dataValidation", {
|
|
10877
10911
|
getProposals(tokenAtCursor, content) {
|
|
10878
|
-
if (content
|
|
10912
|
+
if (isFormula(content)) {
|
|
10879
10913
|
return [];
|
|
10880
10914
|
}
|
|
10881
10915
|
if (!this.composer.currentEditedCell) {
|
|
@@ -18684,7 +18718,7 @@ const HLOOKUP = {
|
|
|
18684
18718
|
const _isSorted = toBoolean(isSorted.value);
|
|
18685
18719
|
const colIndex = _isSorted
|
|
18686
18720
|
? dichotomicSearch(_range, searchKey, "nextSmaller", "asc", _range.length, getValueFromRange)
|
|
18687
|
-
: linearSearch(_range, searchKey, "wildcard", _range.length, getValueFromRange);
|
|
18721
|
+
: linearSearch(_range, searchKey, "wildcard", _range.length, getValueFromRange, this.lookupCaches);
|
|
18688
18722
|
const col = _range[colIndex];
|
|
18689
18723
|
if (col === undefined) {
|
|
18690
18724
|
return valueNotAvailable(searchKey);
|
|
@@ -18839,7 +18873,7 @@ const MATCH = {
|
|
|
18839
18873
|
index = dichotomicSearch(_range, searchKey, "nextSmaller", "asc", rangeLen, getElement);
|
|
18840
18874
|
break;
|
|
18841
18875
|
case 0:
|
|
18842
|
-
index = linearSearch(_range, searchKey, "wildcard", rangeLen, getElement);
|
|
18876
|
+
index = linearSearch(_range, searchKey, "wildcard", rangeLen, getElement, this.lookupCaches);
|
|
18843
18877
|
break;
|
|
18844
18878
|
case -1:
|
|
18845
18879
|
index = dichotomicSearch(_range, searchKey, "nextGreater", "desc", rangeLen, getElement);
|
|
@@ -18907,7 +18941,7 @@ const VLOOKUP = {
|
|
|
18907
18941
|
const _isSorted = toBoolean(isSorted.value);
|
|
18908
18942
|
const rowIndex = _isSorted
|
|
18909
18943
|
? dichotomicSearch(_range, searchKey, "nextSmaller", "asc", _range[0].length, getValueFromRange)
|
|
18910
|
-
: linearSearch(_range, searchKey, "wildcard", _range[0].length, getValueFromRange);
|
|
18944
|
+
: linearSearch(_range, searchKey, "wildcard", _range[0].length, getValueFromRange, this.lookupCaches);
|
|
18911
18945
|
const value = _range[_index - 1][rowIndex];
|
|
18912
18946
|
if (value === undefined) {
|
|
18913
18947
|
return valueNotAvailable(searchKey);
|
|
@@ -18963,7 +18997,7 @@ const XLOOKUP = {
|
|
|
18963
18997
|
const reverseSearch = _searchMode === -1;
|
|
18964
18998
|
const index = _searchMode === 2 || _searchMode === -2
|
|
18965
18999
|
? dichotomicSearch(_lookupRange, searchKey, mode, _searchMode === 2 ? "asc" : "desc", rangeLen, getElement)
|
|
18966
|
-
: linearSearch(_lookupRange, searchKey, mode, rangeLen, getElement, reverseSearch);
|
|
19000
|
+
: linearSearch(_lookupRange, searchKey, mode, rangeLen, getElement, this.lookupCaches, reverseSearch);
|
|
18967
19001
|
if (index !== -1) {
|
|
18968
19002
|
return lookupDirection === "col"
|
|
18969
19003
|
? _returnRange.map((col) => [col[index]])
|
|
@@ -20421,7 +20455,7 @@ autoCompleteProviders.add("functions", {
|
|
|
20421
20455
|
return [];
|
|
20422
20456
|
}
|
|
20423
20457
|
const searchTerm = tokenAtCursor.value;
|
|
20424
|
-
if (!this.composer.currentContent
|
|
20458
|
+
if (!isFormula(this.composer.currentContent)) {
|
|
20425
20459
|
return [];
|
|
20426
20460
|
}
|
|
20427
20461
|
const values = Object.entries(functionRegistry.content)
|
|
@@ -20829,7 +20863,7 @@ class AbstractComposerStore extends SpreadsheetStore {
|
|
|
20829
20863
|
return;
|
|
20830
20864
|
}
|
|
20831
20865
|
if (content) {
|
|
20832
|
-
if (content
|
|
20866
|
+
if (isFormula(content)) {
|
|
20833
20867
|
const left = this.currentTokens.filter((t) => t.type === "LEFT_PAREN").length;
|
|
20834
20868
|
const right = this.currentTokens.filter((t) => t.type === "RIGHT_PAREN").length;
|
|
20835
20869
|
const missing = left - right;
|
|
@@ -20883,7 +20917,7 @@ class AbstractComposerStore extends SpreadsheetStore {
|
|
|
20883
20917
|
}
|
|
20884
20918
|
if (isNewCurrentContent || this.editionMode !== "inactive") {
|
|
20885
20919
|
const locale = this.getters.getLocale();
|
|
20886
|
-
this.currentTokens = text
|
|
20920
|
+
this.currentTokens = isFormula(text) ? composerTokenize(text, locale) : [];
|
|
20887
20921
|
if (this.currentTokens.length > 100) {
|
|
20888
20922
|
if (raise) {
|
|
20889
20923
|
this.notificationStore.raiseError(_t("This formula has over 100 parts. It can't be processed properly, consider splitting it into multiple cells"));
|
|
@@ -21083,7 +21117,7 @@ class AbstractComposerStore extends SpreadsheetStore {
|
|
|
21083
21117
|
}
|
|
21084
21118
|
}
|
|
21085
21119
|
updateRangeColor() {
|
|
21086
|
-
if (!this._currentContent
|
|
21120
|
+
if (!isFormula(this._currentContent) || this.editionMode === "inactive") {
|
|
21087
21121
|
return;
|
|
21088
21122
|
}
|
|
21089
21123
|
const editionSheetId = this.sheetId;
|
|
@@ -21112,7 +21146,7 @@ class AbstractComposerStore extends SpreadsheetStore {
|
|
|
21112
21146
|
* Highlight all ranges that can be found in the composer content.
|
|
21113
21147
|
*/
|
|
21114
21148
|
get highlights() {
|
|
21115
|
-
if (!this.currentContent
|
|
21149
|
+
if (!isFormula(this.currentContent) || this.editionMode === "inactive") {
|
|
21116
21150
|
return [];
|
|
21117
21151
|
}
|
|
21118
21152
|
const editionSheetId = this.sheetId;
|
|
@@ -21146,7 +21180,7 @@ class AbstractComposerStore extends SpreadsheetStore {
|
|
|
21146
21180
|
}
|
|
21147
21181
|
get autocompleteProvider() {
|
|
21148
21182
|
const content = this.currentContent;
|
|
21149
|
-
const tokenAtCursor = content
|
|
21183
|
+
const tokenAtCursor = isFormula(content)
|
|
21150
21184
|
? this.tokenAtCursor
|
|
21151
21185
|
: { type: "STRING", value: content };
|
|
21152
21186
|
if (this.editionMode === "inactive" ||
|
|
@@ -21203,7 +21237,7 @@ class AbstractComposerStore extends SpreadsheetStore {
|
|
|
21203
21237
|
* - Previous and next tokens can be separated by spaces
|
|
21204
21238
|
*/
|
|
21205
21239
|
canStartComposerRangeSelection() {
|
|
21206
|
-
if (this._currentContent
|
|
21240
|
+
if (isFormula(this._currentContent)) {
|
|
21207
21241
|
const tokenAtCursor = this.tokenAtCursor;
|
|
21208
21242
|
if (!tokenAtCursor) {
|
|
21209
21243
|
return false;
|
|
@@ -28302,7 +28336,7 @@ function getBarChartData(definition, dataSets, labelRange, getters) {
|
|
|
28302
28336
|
}
|
|
28303
28337
|
function getPyramidChartData(definition, dataSets, labelRange, getters) {
|
|
28304
28338
|
const barChartData = getBarChartData(definition, dataSets, labelRange, getters);
|
|
28305
|
-
const barDataset = barChartData.dataSetsValues;
|
|
28339
|
+
const barDataset = barChartData.dataSetsValues.filter((ds) => !ds.hidden);
|
|
28306
28340
|
const pyramidDatasetValues = [];
|
|
28307
28341
|
if (barDataset[0]) {
|
|
28308
28342
|
const pyramidData = barDataset[0].data.map((value) => (value > 0 ? value : 0));
|
|
@@ -28779,10 +28813,8 @@ function getChartDatasetFormat(getters, allDataSets, axis) {
|
|
|
28779
28813
|
function getChartDatasetValues(getters, dataSets) {
|
|
28780
28814
|
const datasetValues = [];
|
|
28781
28815
|
for (const [dsIndex, ds] of Object.entries(dataSets)) {
|
|
28782
|
-
if (getters.isColHidden(ds.dataRange.sheetId, ds.dataRange.zone.left)) {
|
|
28783
|
-
continue;
|
|
28784
|
-
}
|
|
28785
28816
|
let label;
|
|
28817
|
+
let hidden = getters.isColHidden(ds.dataRange.sheetId, ds.dataRange.zone.left);
|
|
28786
28818
|
if (ds.labelCell) {
|
|
28787
28819
|
const labelRange = ds.labelCell;
|
|
28788
28820
|
const cell = labelRange
|
|
@@ -28809,9 +28841,9 @@ function getChartDatasetValues(getters, dataSets) {
|
|
|
28809
28841
|
data.fill(1);
|
|
28810
28842
|
}
|
|
28811
28843
|
else if (data.every((cell) => cell === undefined || cell === null || !isNumber(cell.toString(), DEFAULT_LOCALE))) {
|
|
28812
|
-
|
|
28844
|
+
hidden = true;
|
|
28813
28845
|
}
|
|
28814
|
-
datasetValues.push({ data, label });
|
|
28846
|
+
datasetValues.push({ data, label, hidden });
|
|
28815
28847
|
}
|
|
28816
28848
|
return datasetValues;
|
|
28817
28849
|
}
|
|
@@ -28822,12 +28854,13 @@ function getBarChartDatasets(definition, args) {
|
|
|
28822
28854
|
const colors = getChartColorsGenerator(definition, dataSetsValues.length);
|
|
28823
28855
|
const trendDatasets = [];
|
|
28824
28856
|
for (const index in dataSetsValues) {
|
|
28825
|
-
let { label, data } = dataSetsValues[index];
|
|
28857
|
+
let { label, data, hidden } = dataSetsValues[index];
|
|
28826
28858
|
label = definition.dataSets?.[index].label || label;
|
|
28827
28859
|
const backgroundColor = colors.next();
|
|
28828
28860
|
const dataset = {
|
|
28829
28861
|
label,
|
|
28830
28862
|
data,
|
|
28863
|
+
hidden,
|
|
28831
28864
|
borderColor: definition.background || BACKGROUND_CHART_COLOR,
|
|
28832
28865
|
borderWidth: definition.stacked ? 1 : 0,
|
|
28833
28866
|
backgroundColor,
|
|
@@ -28860,6 +28893,9 @@ function getWaterfallDatasetAndLabels(definition, args) {
|
|
|
28860
28893
|
const labelsWithSubTotals = [];
|
|
28861
28894
|
let lastValue = 0;
|
|
28862
28895
|
for (const dataSetsValue of dataSetsValues) {
|
|
28896
|
+
if (dataSetsValue.hidden) {
|
|
28897
|
+
continue;
|
|
28898
|
+
}
|
|
28863
28899
|
for (let i = 0; i < dataSetsValue.data.length; i++) {
|
|
28864
28900
|
const data = dataSetsValue.data[i];
|
|
28865
28901
|
labelsWithSubTotals.push(labels[i]);
|
|
@@ -28895,7 +28931,7 @@ function getLineChartDatasets(definition, args) {
|
|
|
28895
28931
|
const trendDatasets = [];
|
|
28896
28932
|
const colors = getChartColorsGenerator(definition, dataSetsValues.length);
|
|
28897
28933
|
for (let index = 0; index < dataSetsValues.length; index++) {
|
|
28898
|
-
let { label, data } = dataSetsValues[index];
|
|
28934
|
+
let { label, data, hidden } = dataSetsValues[index];
|
|
28899
28935
|
label = definition.dataSets?.[index].label || label;
|
|
28900
28936
|
const color = colors.next();
|
|
28901
28937
|
if (axisType && ["linear", "time"].includes(axisType)) {
|
|
@@ -28905,6 +28941,7 @@ function getLineChartDatasets(definition, args) {
|
|
|
28905
28941
|
const dataset = {
|
|
28906
28942
|
label,
|
|
28907
28943
|
data,
|
|
28944
|
+
hidden,
|
|
28908
28945
|
tension: 0, // 0 -> render straight lines, which is much faster
|
|
28909
28946
|
borderColor: color,
|
|
28910
28947
|
backgroundColor: areaChart ? setColorAlpha(color, LINE_FILL_TRANSPARENCY) : color,
|
|
@@ -28937,7 +28974,9 @@ function getPieChartDatasets(definition, args) {
|
|
|
28937
28974
|
const dataSets = [];
|
|
28938
28975
|
const dataSetsLength = Math.max(0, ...dataSetsValues.map((ds) => ds?.data?.length ?? 0));
|
|
28939
28976
|
const backgroundColor = getPieColors(new ColorGenerator(dataSetsLength), dataSetsValues);
|
|
28940
|
-
for (const { label, data } of dataSetsValues) {
|
|
28977
|
+
for (const { label, data, hidden } of dataSetsValues) {
|
|
28978
|
+
if (hidden)
|
|
28979
|
+
continue;
|
|
28941
28980
|
const dataset = {
|
|
28942
28981
|
label,
|
|
28943
28982
|
data,
|
|
@@ -28955,7 +28994,7 @@ function getComboChartDatasets(definition, args) {
|
|
|
28955
28994
|
const colors = getChartColorsGenerator(definition, dataSetsValues.length);
|
|
28956
28995
|
const trendDatasets = [];
|
|
28957
28996
|
for (let index = 0; index < dataSetsValues.length; index++) {
|
|
28958
|
-
let { label, data } = dataSetsValues[index];
|
|
28997
|
+
let { label, data, hidden } = dataSetsValues[index];
|
|
28959
28998
|
label = definition.dataSets?.[index].label || label;
|
|
28960
28999
|
const design = definition.dataSets?.[index];
|
|
28961
29000
|
const color = colors.next();
|
|
@@ -28963,6 +29002,7 @@ function getComboChartDatasets(definition, args) {
|
|
|
28963
29002
|
const dataset = {
|
|
28964
29003
|
label: label,
|
|
28965
29004
|
data,
|
|
29005
|
+
hidden,
|
|
28966
29006
|
borderColor: color,
|
|
28967
29007
|
backgroundColor: color,
|
|
28968
29008
|
yAxisID: definition.dataSets?.[index].yAxisId || "y",
|
|
@@ -28987,7 +29027,7 @@ function getRadarChartDatasets(definition, args) {
|
|
|
28987
29027
|
const fill = definition.fillArea ?? false;
|
|
28988
29028
|
const colors = getChartColorsGenerator(definition, dataSetsValues.length);
|
|
28989
29029
|
for (let i = 0; i < dataSetsValues.length; i++) {
|
|
28990
|
-
let { label, data } = dataSetsValues[i];
|
|
29030
|
+
let { label, data, hidden } = dataSetsValues[i];
|
|
28991
29031
|
if (definition.dataSets?.[i]?.label) {
|
|
28992
29032
|
label = definition.dataSets[i].label;
|
|
28993
29033
|
}
|
|
@@ -28995,6 +29035,7 @@ function getRadarChartDatasets(definition, args) {
|
|
|
28995
29035
|
const dataset = {
|
|
28996
29036
|
label,
|
|
28997
29037
|
data,
|
|
29038
|
+
hidden,
|
|
28998
29039
|
borderColor,
|
|
28999
29040
|
backgroundColor: borderColor,
|
|
29000
29041
|
};
|
|
@@ -29140,6 +29181,11 @@ function getPieChartLegend(definition, args) {
|
|
|
29140
29181
|
hidden: false,
|
|
29141
29182
|
lineWidth: 2,
|
|
29142
29183
|
})),
|
|
29184
|
+
filter: (legendItem, data) => {
|
|
29185
|
+
return "datasetIndex" in legendItem
|
|
29186
|
+
? !data.datasets[legendItem.datasetIndex].hidden
|
|
29187
|
+
: true;
|
|
29188
|
+
},
|
|
29143
29189
|
},
|
|
29144
29190
|
};
|
|
29145
29191
|
}
|
|
@@ -29201,6 +29247,11 @@ function getWaterfallChartLegend(definition, args) {
|
|
|
29201
29247
|
}
|
|
29202
29248
|
return legendValues;
|
|
29203
29249
|
},
|
|
29250
|
+
filter: (legendItem, data) => {
|
|
29251
|
+
return "datasetIndex" in legendItem
|
|
29252
|
+
? !data.datasets[legendItem.datasetIndex].hidden
|
|
29253
|
+
: true;
|
|
29254
|
+
},
|
|
29204
29255
|
},
|
|
29205
29256
|
onClick: () => { }, // Disables click interaction with the waterfall chart legend items
|
|
29206
29257
|
};
|
|
@@ -29284,6 +29335,11 @@ function getCustomLegendLabels(fontColor, legendLabelConfig) {
|
|
|
29284
29335
|
...legendLabelConfig,
|
|
29285
29336
|
};
|
|
29286
29337
|
}),
|
|
29338
|
+
filter: (legendItem, data) => {
|
|
29339
|
+
return "datasetIndex" in legendItem
|
|
29340
|
+
? !data.datasets[legendItem.datasetIndex].hidden
|
|
29341
|
+
: true;
|
|
29342
|
+
},
|
|
29287
29343
|
},
|
|
29288
29344
|
};
|
|
29289
29345
|
}
|
|
@@ -29617,7 +29673,7 @@ const templates = /* xml */ `
|
|
|
29617
29673
|
<div
|
|
29618
29674
|
class="o-chart-custom-tooltip border rounded px-2 py-1 pe-none mw-100 position-absolute text-nowrap shadow opacity-100">
|
|
29619
29675
|
<table class="overflow-hidden m-0">
|
|
29620
|
-
<thead>
|
|
29676
|
+
<thead t-if="title">
|
|
29621
29677
|
<tr>
|
|
29622
29678
|
<th class="o-tooltip-title align-baseline border-0 text-truncate" t-esc="title" t-attf-style="max-width: {{ labelsMaxWidth }}"/>
|
|
29623
29679
|
</tr>
|
|
@@ -29678,8 +29734,8 @@ function getBarChartTooltip(definition, args) {
|
|
|
29678
29734
|
? undefined
|
|
29679
29735
|
: "";
|
|
29680
29736
|
},
|
|
29737
|
+
beforeLabel: (tooltipItem) => tooltipItem.dataset?.label || tooltipItem.label,
|
|
29681
29738
|
label: function (tooltipItem) {
|
|
29682
|
-
const xLabel = tooltipItem.dataset?.label || tooltipItem.label;
|
|
29683
29739
|
const horizontalChart = definition.horizontal;
|
|
29684
29740
|
let yLabel = horizontalChart ? tooltipItem.parsed.x : tooltipItem.parsed.y;
|
|
29685
29741
|
if (yLabel === undefined || yLabel === null) {
|
|
@@ -29687,7 +29743,7 @@ function getBarChartTooltip(definition, args) {
|
|
|
29687
29743
|
}
|
|
29688
29744
|
const axisId = horizontalChart ? tooltipItem.dataset.xAxisID : tooltipItem.dataset.yAxisID;
|
|
29689
29745
|
const yLabelStr = formatChartDatasetValue(args.axisFormats, args.locale)(yLabel, axisId);
|
|
29690
|
-
return
|
|
29746
|
+
return yLabelStr;
|
|
29691
29747
|
},
|
|
29692
29748
|
},
|
|
29693
29749
|
};
|
|
@@ -29712,21 +29768,18 @@ function getLineChartTooltip(definition, args) {
|
|
|
29712
29768
|
const formattedX = formatValue(label, { locale, format: labelFormat });
|
|
29713
29769
|
const axisId = tooltipItem.dataset.yAxisID || "y";
|
|
29714
29770
|
const formattedY = formatValue(dataSetPoint, { locale, format: axisFormats?.[axisId] });
|
|
29715
|
-
|
|
29716
|
-
return formattedX
|
|
29717
|
-
? `${dataSetTitle}: (${formattedX}, ${formattedY})`
|
|
29718
|
-
: `${dataSetTitle}: ${formattedY}`;
|
|
29771
|
+
return formattedX ? `(${formattedX}, ${formattedY})` : `${formattedY}`;
|
|
29719
29772
|
};
|
|
29720
29773
|
}
|
|
29721
29774
|
else {
|
|
29722
29775
|
tooltip.callbacks.label = function (tooltipItem) {
|
|
29723
|
-
const xLabel = tooltipItem.dataset?.label || tooltipItem.label;
|
|
29724
29776
|
const yLabel = tooltipItem.parsed.y;
|
|
29725
29777
|
const axisId = tooltipItem.dataset.yAxisID;
|
|
29726
29778
|
const yLabelStr = formatChartDatasetValue(axisFormats, locale)(yLabel, axisId);
|
|
29727
|
-
return
|
|
29779
|
+
return yLabelStr;
|
|
29728
29780
|
};
|
|
29729
29781
|
}
|
|
29782
|
+
tooltip.callbacks.beforeLabel = (tooltipItem) => tooltipItem.dataset?.label || tooltipItem.label;
|
|
29730
29783
|
tooltip.callbacks.title = function (tooltipItems) {
|
|
29731
29784
|
const displayTooltipTitle = axisType !== "linear" &&
|
|
29732
29785
|
tooltipItems.some((item) => item.dataset.xAxisID !== TREND_LINE_XAXIS_ID);
|
|
@@ -29744,17 +29797,15 @@ function getPieChartTooltip(definition, args) {
|
|
|
29744
29797
|
title: function (tooltipItems) {
|
|
29745
29798
|
return tooltipItems[0].dataset.label;
|
|
29746
29799
|
},
|
|
29800
|
+
beforeLabel: (tooltipItem) => tooltipItem.label || tooltipItem.dataset.label,
|
|
29747
29801
|
label: function (tooltipItem) {
|
|
29748
29802
|
const data = tooltipItem.dataset.data;
|
|
29749
29803
|
const dataIndex = tooltipItem.dataIndex;
|
|
29750
29804
|
const percentage = calculatePercentage(data, dataIndex);
|
|
29751
|
-
const xLabel = tooltipItem.label || tooltipItem.dataset.label;
|
|
29752
29805
|
const yLabel = tooltipItem.parsed.y ?? tooltipItem.parsed;
|
|
29753
29806
|
const toolTipFormat = !format && yLabel >= 1000 ? "#,##" : format;
|
|
29754
29807
|
const yLabelStr = formatValue(yLabel, { format: toolTipFormat, locale });
|
|
29755
|
-
return
|
|
29756
|
-
? `${xLabel}: ${yLabelStr} (${percentage}%)`
|
|
29757
|
-
: `${yLabelStr} (${percentage}%)`;
|
|
29808
|
+
return `${yLabelStr} (${percentage}%)`;
|
|
29758
29809
|
},
|
|
29759
29810
|
},
|
|
29760
29811
|
};
|
|
@@ -29767,16 +29818,17 @@ function getWaterfallChartTooltip(definition, args) {
|
|
|
29767
29818
|
enabled: false,
|
|
29768
29819
|
external: customTooltipHandler,
|
|
29769
29820
|
callbacks: {
|
|
29770
|
-
|
|
29771
|
-
const [lastValue, currentValue] = tooltipItem.raw;
|
|
29772
|
-
const yLabel = currentValue - lastValue;
|
|
29821
|
+
beforeLabel: function (tooltipItem) {
|
|
29773
29822
|
const dataSeriesIndex = labels.length
|
|
29774
29823
|
? Math.floor(tooltipItem.dataIndex / labels.length)
|
|
29775
29824
|
: 0;
|
|
29776
|
-
|
|
29825
|
+
return dataSeriesLabels[dataSeriesIndex];
|
|
29826
|
+
},
|
|
29827
|
+
label: function (tooltipItem) {
|
|
29828
|
+
const [lastValue, currentValue] = tooltipItem.raw;
|
|
29829
|
+
const yLabel = currentValue - lastValue;
|
|
29777
29830
|
const toolTipFormat = !format && Math.abs(yLabel) > 1000 ? "#,##" : format;
|
|
29778
|
-
|
|
29779
|
-
return dataSeriesLabel ? `${dataSeriesLabel}: ${yLabelStr}` : yLabelStr;
|
|
29831
|
+
return formatValue(yLabel, { format: toolTipFormat, locale });
|
|
29780
29832
|
},
|
|
29781
29833
|
},
|
|
29782
29834
|
};
|
|
@@ -29800,11 +29852,10 @@ function getRadarChartTooltip(definition, args) {
|
|
|
29800
29852
|
enabled: false,
|
|
29801
29853
|
external: customTooltipHandler,
|
|
29802
29854
|
callbacks: {
|
|
29855
|
+
beforeLabel: (tooltipItem) => tooltipItem.dataset?.label || tooltipItem.label,
|
|
29803
29856
|
label: function (tooltipItem) {
|
|
29804
|
-
const xLabel = tooltipItem.dataset?.label || tooltipItem.label;
|
|
29805
29857
|
const yLabel = tooltipItem.parsed.r;
|
|
29806
|
-
|
|
29807
|
-
return xLabel ? `${xLabel}: ${formattedY}` : formattedY;
|
|
29858
|
+
return formatValue(yLabel, { format: axisFormats?.r, locale });
|
|
29808
29859
|
},
|
|
29809
29860
|
},
|
|
29810
29861
|
};
|
|
@@ -29819,13 +29870,12 @@ function getGeoChartTooltip(definition, args) {
|
|
|
29819
29870
|
return tooltipItem.raw.value !== undefined;
|
|
29820
29871
|
},
|
|
29821
29872
|
callbacks: {
|
|
29873
|
+
beforeLabel: (tooltipItem) => tooltipItem.raw.feature.properties.name,
|
|
29822
29874
|
label: function (tooltipItem) {
|
|
29823
29875
|
const rawItem = tooltipItem.raw;
|
|
29824
|
-
const xLabel = rawItem.feature.properties.name;
|
|
29825
29876
|
const yLabel = rawItem.value;
|
|
29826
29877
|
const toolTipFormat = !format && Math.abs(yLabel) >= 1000 ? "#,##" : format;
|
|
29827
|
-
|
|
29828
|
-
return xLabel ? `${xLabel}: ${yLabelStr}` : yLabelStr;
|
|
29878
|
+
return formatValue(yLabel, { format: toolTipFormat, locale });
|
|
29829
29879
|
},
|
|
29830
29880
|
},
|
|
29831
29881
|
};
|
|
@@ -29845,7 +29895,8 @@ function customTooltipHandler({ chart, tooltip }) {
|
|
|
29845
29895
|
return;
|
|
29846
29896
|
}
|
|
29847
29897
|
const tooltipItems = tooltip.body.map((body, index) => {
|
|
29848
|
-
let
|
|
29898
|
+
let label = body.before[0];
|
|
29899
|
+
let value = body.lines[0];
|
|
29849
29900
|
if (!value) {
|
|
29850
29901
|
value = label;
|
|
29851
29902
|
label = "";
|
|
@@ -33006,6 +33057,187 @@ const FilterMenuPopoverBuilder = {
|
|
|
33006
33057
|
},
|
|
33007
33058
|
};
|
|
33008
33059
|
|
|
33060
|
+
const macRegex = /Mac/i;
|
|
33061
|
+
const MODIFIER_KEYS = ["Shift", "Control", "Alt", "Meta"];
|
|
33062
|
+
/**
|
|
33063
|
+
* Return true if the event was triggered from
|
|
33064
|
+
* a child element.
|
|
33065
|
+
*/
|
|
33066
|
+
function isChildEvent(parent, ev) {
|
|
33067
|
+
if (!parent)
|
|
33068
|
+
return false;
|
|
33069
|
+
return !!ev.target && parent.contains(ev.target);
|
|
33070
|
+
}
|
|
33071
|
+
function gridOverlayPosition() {
|
|
33072
|
+
const spreadsheetElement = document.querySelector(".o-grid-overlay");
|
|
33073
|
+
if (spreadsheetElement) {
|
|
33074
|
+
const { top, left } = spreadsheetElement?.getBoundingClientRect();
|
|
33075
|
+
return { top, left };
|
|
33076
|
+
}
|
|
33077
|
+
throw new Error("Can't find spreadsheet position");
|
|
33078
|
+
}
|
|
33079
|
+
function getBoundingRectAsPOJO(el) {
|
|
33080
|
+
const rect = el.getBoundingClientRect();
|
|
33081
|
+
return {
|
|
33082
|
+
x: rect.x,
|
|
33083
|
+
y: rect.y,
|
|
33084
|
+
width: rect.width,
|
|
33085
|
+
height: rect.height,
|
|
33086
|
+
};
|
|
33087
|
+
}
|
|
33088
|
+
/**
|
|
33089
|
+
* Iterate over all the children of `el` in the dom tree starting at `el`, depth first.
|
|
33090
|
+
*/
|
|
33091
|
+
function* iterateChildren(el) {
|
|
33092
|
+
yield el;
|
|
33093
|
+
if (el.hasChildNodes()) {
|
|
33094
|
+
for (let child of el.childNodes) {
|
|
33095
|
+
yield* iterateChildren(child);
|
|
33096
|
+
}
|
|
33097
|
+
}
|
|
33098
|
+
}
|
|
33099
|
+
function getOpenedMenus() {
|
|
33100
|
+
return Array.from(document.querySelectorAll(".o-spreadsheet .o-menu"));
|
|
33101
|
+
}
|
|
33102
|
+
function getCurrentSelection(el) {
|
|
33103
|
+
let { startElement, endElement, startSelectionOffset, endSelectionOffset } = getStartAndEndSelection(el);
|
|
33104
|
+
let startSizeBefore = findSelectionIndex(el, startElement, startSelectionOffset);
|
|
33105
|
+
let endSizeBefore = findSelectionIndex(el, endElement, endSelectionOffset);
|
|
33106
|
+
return {
|
|
33107
|
+
start: startSizeBefore,
|
|
33108
|
+
end: endSizeBefore,
|
|
33109
|
+
};
|
|
33110
|
+
}
|
|
33111
|
+
function getStartAndEndSelection(el) {
|
|
33112
|
+
const selection = document.getSelection();
|
|
33113
|
+
return {
|
|
33114
|
+
startElement: selection.anchorNode || el,
|
|
33115
|
+
startSelectionOffset: selection.anchorOffset,
|
|
33116
|
+
endElement: selection.focusNode || el,
|
|
33117
|
+
endSelectionOffset: selection.focusOffset,
|
|
33118
|
+
};
|
|
33119
|
+
}
|
|
33120
|
+
/**
|
|
33121
|
+
* Computes the text 'index' inside this.el based on the currently selected node and its offset.
|
|
33122
|
+
* The selected node is either a Text node or an Element node.
|
|
33123
|
+
*
|
|
33124
|
+
* case 1 -Text node:
|
|
33125
|
+
* the offset is the number of characters from the start of the node. We have to add this offset to the
|
|
33126
|
+
* content length of all previous nodes.
|
|
33127
|
+
*
|
|
33128
|
+
* case 2 - Element node:
|
|
33129
|
+
* the offset is the number of child nodes before the selected node. We have to add the content length of
|
|
33130
|
+
* all the nodes prior to the selected node as well as the content of the child node before the offset.
|
|
33131
|
+
*
|
|
33132
|
+
* See the MDN documentation for more details.
|
|
33133
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/Range/startOffset
|
|
33134
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/Range/endOffset
|
|
33135
|
+
*
|
|
33136
|
+
*/
|
|
33137
|
+
function findSelectionIndex(el, nodeToFind, nodeOffset) {
|
|
33138
|
+
let usedCharacters = 0;
|
|
33139
|
+
let it = iterateChildren(el);
|
|
33140
|
+
let current = it.next();
|
|
33141
|
+
let isFirstParagraph = true;
|
|
33142
|
+
while (!current.done && current.value !== nodeToFind) {
|
|
33143
|
+
if (!current.value.hasChildNodes()) {
|
|
33144
|
+
if (current.value.textContent) {
|
|
33145
|
+
usedCharacters += current.value.textContent.length;
|
|
33146
|
+
}
|
|
33147
|
+
}
|
|
33148
|
+
// One new paragraph = one new line character, except for the first paragraph
|
|
33149
|
+
if (current.value.nodeName === "P" ||
|
|
33150
|
+
(current.value.nodeName === "DIV" && current.value !== el) // On paste, the HTML may contain <div> instead of <p>
|
|
33151
|
+
) {
|
|
33152
|
+
if (isFirstParagraph) {
|
|
33153
|
+
isFirstParagraph = false;
|
|
33154
|
+
}
|
|
33155
|
+
else {
|
|
33156
|
+
usedCharacters++;
|
|
33157
|
+
}
|
|
33158
|
+
}
|
|
33159
|
+
current = it.next();
|
|
33160
|
+
}
|
|
33161
|
+
if (current.value !== nodeToFind) {
|
|
33162
|
+
/** This situation can happen if the code is called while the selection is not currently on the element.
|
|
33163
|
+
* In this case, we return 0 because we don't know the size of the text before the selection.
|
|
33164
|
+
*
|
|
33165
|
+
* A known occurrence is triggered since the introduction of commit d4663158 (PR #2038).
|
|
33166
|
+
*/
|
|
33167
|
+
return 0;
|
|
33168
|
+
}
|
|
33169
|
+
else {
|
|
33170
|
+
if (!current.value.hasChildNodes()) {
|
|
33171
|
+
usedCharacters += nodeOffset;
|
|
33172
|
+
}
|
|
33173
|
+
else {
|
|
33174
|
+
const children = [...current.value.childNodes].slice(0, nodeOffset);
|
|
33175
|
+
usedCharacters += children.reduce((acc, child, index) => {
|
|
33176
|
+
if (child.textContent !== null) {
|
|
33177
|
+
// need to account for paragraph nodes that implicitly add a new line
|
|
33178
|
+
// except for the last paragraph
|
|
33179
|
+
let chars = child.textContent.length;
|
|
33180
|
+
if (child.nodeName === "P" && index !== children.length - 1) {
|
|
33181
|
+
chars++;
|
|
33182
|
+
}
|
|
33183
|
+
return acc + chars;
|
|
33184
|
+
}
|
|
33185
|
+
else {
|
|
33186
|
+
return acc;
|
|
33187
|
+
}
|
|
33188
|
+
}, 0);
|
|
33189
|
+
}
|
|
33190
|
+
}
|
|
33191
|
+
if (nodeToFind.nodeName === "P" && !isFirstParagraph && nodeToFind.textContent === "") {
|
|
33192
|
+
usedCharacters++;
|
|
33193
|
+
}
|
|
33194
|
+
return usedCharacters;
|
|
33195
|
+
}
|
|
33196
|
+
const letterRegex = /^[a-zA-Z]$/;
|
|
33197
|
+
/**
|
|
33198
|
+
* Transform a keyboard event into a shortcut string that represent this event. The letters keys will be uppercased.
|
|
33199
|
+
*
|
|
33200
|
+
* @argument ev - The keyboard event to transform
|
|
33201
|
+
* @argument mode - Use either ev.key of ev.code to get the string shortcut
|
|
33202
|
+
*
|
|
33203
|
+
* @example
|
|
33204
|
+
* event : { ctrlKey: true, key: "a" } => "Ctrl+A"
|
|
33205
|
+
* event : { shift: true, alt: true, key: "Home" } => "Alt+Shift+Home"
|
|
33206
|
+
*/
|
|
33207
|
+
function keyboardEventToShortcutString(ev, mode = "key") {
|
|
33208
|
+
let keyDownString = "";
|
|
33209
|
+
if (!MODIFIER_KEYS.includes(ev.key)) {
|
|
33210
|
+
if (isCtrlKey(ev))
|
|
33211
|
+
keyDownString += "Ctrl+";
|
|
33212
|
+
if (ev.altKey)
|
|
33213
|
+
keyDownString += "Alt+";
|
|
33214
|
+
if (ev.shiftKey)
|
|
33215
|
+
keyDownString += "Shift+";
|
|
33216
|
+
}
|
|
33217
|
+
const key = mode === "key" ? ev.key : ev.code;
|
|
33218
|
+
keyDownString += letterRegex.test(key) ? key.toUpperCase() : key;
|
|
33219
|
+
return keyDownString;
|
|
33220
|
+
}
|
|
33221
|
+
function isMacOS() {
|
|
33222
|
+
return Boolean(macRegex.test(navigator.userAgent));
|
|
33223
|
+
}
|
|
33224
|
+
/**
|
|
33225
|
+
* @param {KeyboardEvent | MouseEvent} ev
|
|
33226
|
+
* @returns Returns true if the event was triggered with the "ctrl" modifier pressed.
|
|
33227
|
+
* On Mac, this is the "meta" or "command" key.
|
|
33228
|
+
*/
|
|
33229
|
+
function isCtrlKey(ev) {
|
|
33230
|
+
return isMacOS() ? ev.metaKey : ev.ctrlKey;
|
|
33231
|
+
}
|
|
33232
|
+
/**
|
|
33233
|
+
* @param {MouseEvent} ev - The mouse event.
|
|
33234
|
+
* @returns {boolean} Returns true if the event was triggered by a middle-click
|
|
33235
|
+
* or a Ctrl + Click (Cmd + Click on Mac).
|
|
33236
|
+
*/
|
|
33237
|
+
function isMiddleClickOrCtrlClick(ev) {
|
|
33238
|
+
return ev.button === 1 || (isCtrlKey(ev) && ev.button === 0);
|
|
33239
|
+
}
|
|
33240
|
+
|
|
33009
33241
|
const LINK_TOOLTIP_HEIGHT = 32;
|
|
33010
33242
|
const LINK_TOOLTIP_WIDTH = 220;
|
|
33011
33243
|
css /* scss */ `
|
|
@@ -33080,8 +33312,8 @@ class LinkDisplay extends Component {
|
|
|
33080
33312
|
getUrlRepresentation(link) {
|
|
33081
33313
|
return urlRepresentation(link, this.env.model.getters);
|
|
33082
33314
|
}
|
|
33083
|
-
openLink() {
|
|
33084
|
-
openLink(this.link, this.env);
|
|
33315
|
+
openLink(ev) {
|
|
33316
|
+
openLink(this.link, this.env, isMiddleClickOrCtrlClick(ev));
|
|
33085
33317
|
}
|
|
33086
33318
|
edit() {
|
|
33087
33319
|
const { col, row } = this.props.cellPosition;
|
|
@@ -33210,179 +33442,6 @@ linkMenuRegistry.add("sheet", {
|
|
|
33210
33442
|
sequence: 10,
|
|
33211
33443
|
});
|
|
33212
33444
|
|
|
33213
|
-
const macRegex = /Mac/i;
|
|
33214
|
-
const MODIFIER_KEYS = ["Shift", "Control", "Alt", "Meta"];
|
|
33215
|
-
/**
|
|
33216
|
-
* Return true if the event was triggered from
|
|
33217
|
-
* a child element.
|
|
33218
|
-
*/
|
|
33219
|
-
function isChildEvent(parent, ev) {
|
|
33220
|
-
if (!parent)
|
|
33221
|
-
return false;
|
|
33222
|
-
return !!ev.target && parent.contains(ev.target);
|
|
33223
|
-
}
|
|
33224
|
-
function gridOverlayPosition() {
|
|
33225
|
-
const spreadsheetElement = document.querySelector(".o-grid-overlay");
|
|
33226
|
-
if (spreadsheetElement) {
|
|
33227
|
-
const { top, left } = spreadsheetElement?.getBoundingClientRect();
|
|
33228
|
-
return { top, left };
|
|
33229
|
-
}
|
|
33230
|
-
throw new Error("Can't find spreadsheet position");
|
|
33231
|
-
}
|
|
33232
|
-
function getBoundingRectAsPOJO(el) {
|
|
33233
|
-
const rect = el.getBoundingClientRect();
|
|
33234
|
-
return {
|
|
33235
|
-
x: rect.x,
|
|
33236
|
-
y: rect.y,
|
|
33237
|
-
width: rect.width,
|
|
33238
|
-
height: rect.height,
|
|
33239
|
-
};
|
|
33240
|
-
}
|
|
33241
|
-
/**
|
|
33242
|
-
* Iterate over all the children of `el` in the dom tree starting at `el`, depth first.
|
|
33243
|
-
*/
|
|
33244
|
-
function* iterateChildren(el) {
|
|
33245
|
-
yield el;
|
|
33246
|
-
if (el.hasChildNodes()) {
|
|
33247
|
-
for (let child of el.childNodes) {
|
|
33248
|
-
yield* iterateChildren(child);
|
|
33249
|
-
}
|
|
33250
|
-
}
|
|
33251
|
-
}
|
|
33252
|
-
function getOpenedMenus() {
|
|
33253
|
-
return Array.from(document.querySelectorAll(".o-spreadsheet .o-menu"));
|
|
33254
|
-
}
|
|
33255
|
-
function getCurrentSelection(el) {
|
|
33256
|
-
let { startElement, endElement, startSelectionOffset, endSelectionOffset } = getStartAndEndSelection(el);
|
|
33257
|
-
let startSizeBefore = findSelectionIndex(el, startElement, startSelectionOffset);
|
|
33258
|
-
let endSizeBefore = findSelectionIndex(el, endElement, endSelectionOffset);
|
|
33259
|
-
return {
|
|
33260
|
-
start: startSizeBefore,
|
|
33261
|
-
end: endSizeBefore,
|
|
33262
|
-
};
|
|
33263
|
-
}
|
|
33264
|
-
function getStartAndEndSelection(el) {
|
|
33265
|
-
const selection = document.getSelection();
|
|
33266
|
-
return {
|
|
33267
|
-
startElement: selection.anchorNode || el,
|
|
33268
|
-
startSelectionOffset: selection.anchorOffset,
|
|
33269
|
-
endElement: selection.focusNode || el,
|
|
33270
|
-
endSelectionOffset: selection.focusOffset,
|
|
33271
|
-
};
|
|
33272
|
-
}
|
|
33273
|
-
/**
|
|
33274
|
-
* Computes the text 'index' inside this.el based on the currently selected node and its offset.
|
|
33275
|
-
* The selected node is either a Text node or an Element node.
|
|
33276
|
-
*
|
|
33277
|
-
* case 1 -Text node:
|
|
33278
|
-
* the offset is the number of characters from the start of the node. We have to add this offset to the
|
|
33279
|
-
* content length of all previous nodes.
|
|
33280
|
-
*
|
|
33281
|
-
* case 2 - Element node:
|
|
33282
|
-
* the offset is the number of child nodes before the selected node. We have to add the content length of
|
|
33283
|
-
* all the nodes prior to the selected node as well as the content of the child node before the offset.
|
|
33284
|
-
*
|
|
33285
|
-
* See the MDN documentation for more details.
|
|
33286
|
-
* https://developer.mozilla.org/en-US/docs/Web/API/Range/startOffset
|
|
33287
|
-
* https://developer.mozilla.org/en-US/docs/Web/API/Range/endOffset
|
|
33288
|
-
*
|
|
33289
|
-
*/
|
|
33290
|
-
function findSelectionIndex(el, nodeToFind, nodeOffset) {
|
|
33291
|
-
let usedCharacters = 0;
|
|
33292
|
-
let it = iterateChildren(el);
|
|
33293
|
-
let current = it.next();
|
|
33294
|
-
let isFirstParagraph = true;
|
|
33295
|
-
while (!current.done && current.value !== nodeToFind) {
|
|
33296
|
-
if (!current.value.hasChildNodes()) {
|
|
33297
|
-
if (current.value.textContent) {
|
|
33298
|
-
usedCharacters += current.value.textContent.length;
|
|
33299
|
-
}
|
|
33300
|
-
}
|
|
33301
|
-
// One new paragraph = one new line character, except for the first paragraph
|
|
33302
|
-
if (current.value.nodeName === "P" ||
|
|
33303
|
-
(current.value.nodeName === "DIV" && current.value !== el) // On paste, the HTML may contain <div> instead of <p>
|
|
33304
|
-
) {
|
|
33305
|
-
if (isFirstParagraph) {
|
|
33306
|
-
isFirstParagraph = false;
|
|
33307
|
-
}
|
|
33308
|
-
else {
|
|
33309
|
-
usedCharacters++;
|
|
33310
|
-
}
|
|
33311
|
-
}
|
|
33312
|
-
current = it.next();
|
|
33313
|
-
}
|
|
33314
|
-
if (current.value !== nodeToFind) {
|
|
33315
|
-
/** This situation can happen if the code is called while the selection is not currently on the element.
|
|
33316
|
-
* In this case, we return 0 because we don't know the size of the text before the selection.
|
|
33317
|
-
*
|
|
33318
|
-
* A known occurrence is triggered since the introduction of commit d4663158 (PR #2038).
|
|
33319
|
-
*/
|
|
33320
|
-
return 0;
|
|
33321
|
-
}
|
|
33322
|
-
else {
|
|
33323
|
-
if (!current.value.hasChildNodes()) {
|
|
33324
|
-
usedCharacters += nodeOffset;
|
|
33325
|
-
}
|
|
33326
|
-
else {
|
|
33327
|
-
const children = [...current.value.childNodes].slice(0, nodeOffset);
|
|
33328
|
-
usedCharacters += children.reduce((acc, child, index) => {
|
|
33329
|
-
if (child.textContent !== null) {
|
|
33330
|
-
// need to account for paragraph nodes that implicitly add a new line
|
|
33331
|
-
// except for the last paragraph
|
|
33332
|
-
let chars = child.textContent.length;
|
|
33333
|
-
if (child.nodeName === "P" && index !== children.length - 1) {
|
|
33334
|
-
chars++;
|
|
33335
|
-
}
|
|
33336
|
-
return acc + chars;
|
|
33337
|
-
}
|
|
33338
|
-
else {
|
|
33339
|
-
return acc;
|
|
33340
|
-
}
|
|
33341
|
-
}, 0);
|
|
33342
|
-
}
|
|
33343
|
-
}
|
|
33344
|
-
if (nodeToFind.nodeName === "P" && !isFirstParagraph && nodeToFind.textContent === "") {
|
|
33345
|
-
usedCharacters++;
|
|
33346
|
-
}
|
|
33347
|
-
return usedCharacters;
|
|
33348
|
-
}
|
|
33349
|
-
const letterRegex = /^[a-zA-Z]$/;
|
|
33350
|
-
/**
|
|
33351
|
-
* Transform a keyboard event into a shortcut string that represent this event. The letters keys will be uppercased.
|
|
33352
|
-
*
|
|
33353
|
-
* @argument ev - The keyboard event to transform
|
|
33354
|
-
* @argument mode - Use either ev.key of ev.code to get the string shortcut
|
|
33355
|
-
*
|
|
33356
|
-
* @example
|
|
33357
|
-
* event : { ctrlKey: true, key: "a" } => "Ctrl+A"
|
|
33358
|
-
* event : { shift: true, alt: true, key: "Home" } => "Alt+Shift+Home"
|
|
33359
|
-
*/
|
|
33360
|
-
function keyboardEventToShortcutString(ev, mode = "key") {
|
|
33361
|
-
let keyDownString = "";
|
|
33362
|
-
if (!MODIFIER_KEYS.includes(ev.key)) {
|
|
33363
|
-
if (isCtrlKey(ev))
|
|
33364
|
-
keyDownString += "Ctrl+";
|
|
33365
|
-
if (ev.altKey)
|
|
33366
|
-
keyDownString += "Alt+";
|
|
33367
|
-
if (ev.shiftKey)
|
|
33368
|
-
keyDownString += "Shift+";
|
|
33369
|
-
}
|
|
33370
|
-
const key = mode === "key" ? ev.key : ev.code;
|
|
33371
|
-
keyDownString += letterRegex.test(key) ? key.toUpperCase() : key;
|
|
33372
|
-
return keyDownString;
|
|
33373
|
-
}
|
|
33374
|
-
function isMacOS() {
|
|
33375
|
-
return Boolean(macRegex.test(navigator.userAgent));
|
|
33376
|
-
}
|
|
33377
|
-
/**
|
|
33378
|
-
* @param {KeyboardEvent | MouseEvent} ev
|
|
33379
|
-
* @returns Returns true if the event was triggered with the "ctrl" modifier pressed.
|
|
33380
|
-
* On Mac, this is the "meta" or "command" key.
|
|
33381
|
-
*/
|
|
33382
|
-
function isCtrlKey(ev) {
|
|
33383
|
-
return isMacOS() ? ev.metaKey : ev.ctrlKey;
|
|
33384
|
-
}
|
|
33385
|
-
|
|
33386
33445
|
/**
|
|
33387
33446
|
* Repeatedly calls a callback function with a time delay between calls.
|
|
33388
33447
|
*/
|
|
@@ -33577,8 +33636,8 @@ class Menu extends Component {
|
|
|
33577
33636
|
getIconColor(menu) {
|
|
33578
33637
|
return cssPropertiesToCss({ color: menu.iconColor });
|
|
33579
33638
|
}
|
|
33580
|
-
async activateMenu(menu) {
|
|
33581
|
-
const result = await menu.execute?.(this.env);
|
|
33639
|
+
async activateMenu(menu, isMiddleClick) {
|
|
33640
|
+
const result = await menu.execute?.(this.env, isMiddleClick);
|
|
33582
33641
|
this.close();
|
|
33583
33642
|
this.props.onMenuClicked?.({ detail: result });
|
|
33584
33643
|
}
|
|
@@ -33641,13 +33700,14 @@ class Menu extends Component {
|
|
|
33641
33700
|
this.subMenu.parentMenu = undefined;
|
|
33642
33701
|
}
|
|
33643
33702
|
onClickMenu(menu, ev) {
|
|
33644
|
-
if (this.isEnabled(menu)) {
|
|
33645
|
-
|
|
33646
|
-
|
|
33647
|
-
|
|
33648
|
-
|
|
33649
|
-
|
|
33650
|
-
|
|
33703
|
+
if (!this.isEnabled(menu)) {
|
|
33704
|
+
return;
|
|
33705
|
+
}
|
|
33706
|
+
if (this.isRoot(menu)) {
|
|
33707
|
+
this.openSubMenu(menu, ev.currentTarget);
|
|
33708
|
+
}
|
|
33709
|
+
else {
|
|
33710
|
+
this.activateMenu(menu, isMiddleClickOrCtrlClick(ev));
|
|
33651
33711
|
}
|
|
33652
33712
|
}
|
|
33653
33713
|
onMouseOver(menu, ev) {
|
|
@@ -40275,7 +40335,7 @@ class Composer extends Component {
|
|
|
40275
40335
|
const content = this.props.composerStore.currentContent;
|
|
40276
40336
|
if (this.props.focus === "cellFocus" &&
|
|
40277
40337
|
!this.autoCompleteState.provider &&
|
|
40278
|
-
!content
|
|
40338
|
+
!isFormula(content)) {
|
|
40279
40339
|
this.props.composerStore.stopEdition();
|
|
40280
40340
|
return;
|
|
40281
40341
|
}
|
|
@@ -40492,7 +40552,7 @@ class Composer extends Component {
|
|
|
40492
40552
|
return;
|
|
40493
40553
|
}
|
|
40494
40554
|
const composerContent = this.props.composerStore.currentContent;
|
|
40495
|
-
const isValidFormula = composerContent
|
|
40555
|
+
const isValidFormula = isFormula(composerContent);
|
|
40496
40556
|
if (isValidFormula) {
|
|
40497
40557
|
const tokens = this.props.composerStore.currentTokens;
|
|
40498
40558
|
const currentSelection = this.contentHelper.getCurrentSelection();
|
|
@@ -40549,7 +40609,7 @@ class Composer extends Component {
|
|
|
40549
40609
|
*/
|
|
40550
40610
|
getContentLines() {
|
|
40551
40611
|
let value = this.props.composerStore.currentContent;
|
|
40552
|
-
const isValidFormula = value
|
|
40612
|
+
const isValidFormula = isFormula(value);
|
|
40553
40613
|
if (value === "") {
|
|
40554
40614
|
return [];
|
|
40555
40615
|
}
|
|
@@ -40638,7 +40698,7 @@ class Composer extends Component {
|
|
|
40638
40698
|
this.autoCompleteState.useProvider(autoCompleteProvider);
|
|
40639
40699
|
}
|
|
40640
40700
|
const token = this.props.composerStore.tokenAtCursor;
|
|
40641
|
-
if (content
|
|
40701
|
+
if (isFormula(content) && token && token.type !== "SYMBOL") {
|
|
40642
40702
|
const tokenContext = token.functionContext;
|
|
40643
40703
|
const parentFunction = tokenContext?.parent.toUpperCase();
|
|
40644
40704
|
if (tokenContext &&
|
|
@@ -48696,7 +48756,7 @@ class CellComposerStore extends AbstractComposerStore {
|
|
|
48696
48756
|
}
|
|
48697
48757
|
break;
|
|
48698
48758
|
case "ACTIVATE_SHEET":
|
|
48699
|
-
if (!this._currentContent
|
|
48759
|
+
if (!isFormula(this._currentContent)) {
|
|
48700
48760
|
this._cancelEdition();
|
|
48701
48761
|
this.resetContent();
|
|
48702
48762
|
}
|
|
@@ -48772,7 +48832,7 @@ class CellComposerStore extends AbstractComposerStore {
|
|
|
48772
48832
|
if (content) {
|
|
48773
48833
|
const sheetId = this.getters.getActiveSheetId();
|
|
48774
48834
|
const cell = this.getters.getEvaluatedCell({ sheetId, col: this.col, row: this.row });
|
|
48775
|
-
if (cell.link && !content
|
|
48835
|
+
if (cell.link && !isFormula(content)) {
|
|
48776
48836
|
content = markdownLink(content, cell.link.url);
|
|
48777
48837
|
}
|
|
48778
48838
|
this.addHeadersForSpreadingFormula(content);
|
|
@@ -48832,7 +48892,7 @@ class CellComposerStore extends AbstractComposerStore {
|
|
|
48832
48892
|
}
|
|
48833
48893
|
/** Add headers at the end of the sheet so the formula in the composer has enough space to spread */
|
|
48834
48894
|
addHeadersForSpreadingFormula(content) {
|
|
48835
|
-
if (!content
|
|
48895
|
+
if (!isFormula(content)) {
|
|
48836
48896
|
return;
|
|
48837
48897
|
}
|
|
48838
48898
|
const evaluated = this.getters.evaluateFormula(this.sheetId, content);
|
|
@@ -48865,7 +48925,7 @@ class CellComposerStore extends AbstractComposerStore {
|
|
|
48865
48925
|
checkDataValidation() {
|
|
48866
48926
|
const cellPosition = { sheetId: this.sheetId, col: this.col, row: this.row };
|
|
48867
48927
|
const content = this.getCurrentCanonicalContent();
|
|
48868
|
-
const cellValue = content
|
|
48928
|
+
const cellValue = isFormula(content)
|
|
48869
48929
|
? this.getters.evaluateFormula(this.sheetId, content)
|
|
48870
48930
|
: parseLiteral(content, this.getters.getLocale());
|
|
48871
48931
|
if (isMatrix(cellValue)) {
|
|
@@ -48987,23 +49047,23 @@ class GridComposer extends Component {
|
|
|
48987
49047
|
if (this.composerStore.editionMode === "inactive") {
|
|
48988
49048
|
return `z-index: -1000;`;
|
|
48989
49049
|
}
|
|
48990
|
-
const
|
|
49050
|
+
const _isFormula = isFormula(this.composerStore.currentContent);
|
|
48991
49051
|
const cell = this.env.model.getters.getActiveCell();
|
|
48992
49052
|
const position = this.env.model.getters.getActivePosition();
|
|
48993
49053
|
const style = this.env.model.getters.getCellComputedStyle(position);
|
|
48994
49054
|
// position style
|
|
48995
49055
|
const { x: left, y: top, width, height } = this.rect;
|
|
48996
49056
|
// color style
|
|
48997
|
-
const background = (!
|
|
48998
|
-
const color = (!
|
|
49057
|
+
const background = (!_isFormula && style.fillColor) || "#ffffff";
|
|
49058
|
+
const color = (!_isFormula && style.textColor) || "#000000";
|
|
48999
49059
|
// font style
|
|
49000
|
-
const fontSize = (!
|
|
49001
|
-
const fontWeight = !
|
|
49002
|
-
const fontStyle = !
|
|
49003
|
-
const textDecoration = !
|
|
49060
|
+
const fontSize = (!_isFormula && style.fontSize) || 10;
|
|
49061
|
+
const fontWeight = !_isFormula && style.bold ? "bold" : undefined;
|
|
49062
|
+
const fontStyle = !_isFormula && style.italic ? "italic" : "normal";
|
|
49063
|
+
const textDecoration = !_isFormula ? getTextDecoration(style) : "none";
|
|
49004
49064
|
// align style
|
|
49005
49065
|
let textAlign = "left";
|
|
49006
|
-
if (!
|
|
49066
|
+
if (!_isFormula) {
|
|
49007
49067
|
textAlign = style.align || cell.defaultAlign;
|
|
49008
49068
|
}
|
|
49009
49069
|
const maxHeight = this.props.gridDims.height - this.rect.y;
|
|
@@ -51637,8 +51697,8 @@ class Border extends Component {
|
|
|
51637
51697
|
css /* scss */ `
|
|
51638
51698
|
.o-corner {
|
|
51639
51699
|
position: absolute;
|
|
51640
|
-
height:
|
|
51641
|
-
width:
|
|
51700
|
+
height: 8px;
|
|
51701
|
+
width: 8px;
|
|
51642
51702
|
border: 1px solid white;
|
|
51643
51703
|
}
|
|
51644
51704
|
.o-corner-nw,
|
|
@@ -53203,7 +53263,7 @@ class BordersPlugin extends CorePlugin {
|
|
|
53203
53263
|
this.history.update("borders", sheetId, col, row, "left", border?.left);
|
|
53204
53264
|
if (border?.left &&
|
|
53205
53265
|
col > 0 &&
|
|
53206
|
-
!deepEquals(this.
|
|
53266
|
+
!deepEquals(this.borders[sheetId]?.[col - 1]?.[row]?.right, border?.left)) {
|
|
53207
53267
|
this.history.update("borders", sheetId, col - 1, row, "right", undefined);
|
|
53208
53268
|
}
|
|
53209
53269
|
}
|
|
@@ -53211,7 +53271,7 @@ class BordersPlugin extends CorePlugin {
|
|
|
53211
53271
|
this.history.update("borders", sheetId, col, row, "top", border?.top);
|
|
53212
53272
|
if (border?.top &&
|
|
53213
53273
|
row > 0 &&
|
|
53214
|
-
!deepEquals(this.
|
|
53274
|
+
!deepEquals(this.borders[sheetId]?.[col]?.[row - 1]?.bottom, border?.top)) {
|
|
53215
53275
|
this.history.update("borders", sheetId, col, row - 1, "bottom", undefined);
|
|
53216
53276
|
}
|
|
53217
53277
|
}
|
|
@@ -53219,7 +53279,7 @@ class BordersPlugin extends CorePlugin {
|
|
|
53219
53279
|
this.history.update("borders", sheetId, col, row, "right", border?.right);
|
|
53220
53280
|
if (border?.right &&
|
|
53221
53281
|
col < maxCol &&
|
|
53222
|
-
!deepEquals(this.
|
|
53282
|
+
!deepEquals(this.borders[sheetId]?.[col + 1]?.[row]?.left, border?.right)) {
|
|
53223
53283
|
this.history.update("borders", sheetId, col + 1, row, "left", undefined);
|
|
53224
53284
|
}
|
|
53225
53285
|
}
|
|
@@ -53227,7 +53287,7 @@ class BordersPlugin extends CorePlugin {
|
|
|
53227
53287
|
this.history.update("borders", sheetId, col, row, "bottom", border?.bottom);
|
|
53228
53288
|
if (border?.bottom &&
|
|
53229
53289
|
row < maxRow &&
|
|
53230
|
-
!deepEquals(this.
|
|
53290
|
+
!deepEquals(this.borders[sheetId]?.[col]?.[row + 1]?.top, border?.bottom)) {
|
|
53231
53291
|
this.history.update("borders", sheetId, col, row + 1, "top", undefined);
|
|
53232
53292
|
}
|
|
53233
53293
|
}
|
|
@@ -59999,6 +60059,10 @@ class Evaluator {
|
|
|
59999
60059
|
this.compilationParams = buildCompilationParameters(this.context, this.getters, this.computeAndSave.bind(this));
|
|
60000
60060
|
this.compilationParams.evalContext.updateDependencies = this.updateDependencies.bind(this);
|
|
60001
60061
|
this.compilationParams.evalContext.addDependencies = this.addDependencies.bind(this);
|
|
60062
|
+
this.compilationParams.evalContext.lookupCaches = {
|
|
60063
|
+
forwardSearch: new Map(),
|
|
60064
|
+
reverseSearch: new Map(),
|
|
60065
|
+
};
|
|
60002
60066
|
}
|
|
60003
60067
|
createEmptyPositionSet() {
|
|
60004
60068
|
const sheetSizes = {};
|
|
@@ -68615,7 +68679,7 @@ clickableCellRegistry.add("link", {
|
|
|
68615
68679
|
condition: (position, getters) => {
|
|
68616
68680
|
return !!getters.getEvaluatedCell(position).link;
|
|
68617
68681
|
},
|
|
68618
|
-
execute: (position, env) => openLink(env.model.getters.getEvaluatedCell(position).link, env),
|
|
68682
|
+
execute: (position, env, isMiddleClick) => openLink(env.model.getters.getEvaluatedCell(position).link, env, isMiddleClick),
|
|
68619
68683
|
sequence: 5,
|
|
68620
68684
|
});
|
|
68621
68685
|
|
|
@@ -69600,9 +69664,9 @@ class SpreadsheetDashboard extends Component {
|
|
|
69600
69664
|
getClickableCells() {
|
|
69601
69665
|
return toRaw(this.clickableCellsStore.clickableCells);
|
|
69602
69666
|
}
|
|
69603
|
-
selectClickableCell(clickableCell) {
|
|
69667
|
+
selectClickableCell(ev, clickableCell) {
|
|
69604
69668
|
const { position, action } = clickableCell;
|
|
69605
|
-
action(position, this.env);
|
|
69669
|
+
action(position, this.env, isMiddleClickOrCtrlClick(ev));
|
|
69606
69670
|
}
|
|
69607
69671
|
onClosePopover() {
|
|
69608
69672
|
this.cellPopovers.close();
|
|
@@ -75564,6 +75628,6 @@ const chartHelpers = { ...CHART_HELPERS, ...CHART_RUNTIME_HELPERS };
|
|
|
75564
75628
|
export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, CoreViewPlugin, DispatchResult, EvaluationError, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, chartHelpers, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
|
|
75565
75629
|
|
|
75566
75630
|
|
|
75567
|
-
__info__.version = "18.
|
|
75568
|
-
__info__.date = "2025-02-
|
|
75569
|
-
__info__.hash = "
|
|
75631
|
+
__info__.version = "18.3.0-alpha.1";
|
|
75632
|
+
__info__.date = "2025-02-25T06:00:14.885Z";
|
|
75633
|
+
__info__.hash = "be4d957";
|