@odoo/o-spreadsheet 19.2.0-alpha.1 → 19.2.0-alpha.2
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-engine.d.ts +11 -6
- package/dist/o-spreadsheet-engine.esm.js +183 -32
- package/dist/o-spreadsheet-engine.iife.js +183 -32
- package/dist/o-spreadsheet-engine.min.iife.js +313 -313
- package/dist/o-spreadsheet.d.ts +23 -18
- package/dist/o_spreadsheet.css +20 -10
- package/dist/o_spreadsheet.esm.js +741 -620
- package/dist/o_spreadsheet.iife.js +741 -620
- package/dist/o_spreadsheet.min.iife.js +9 -9
- package/dist/o_spreadsheet.xml +98 -106
- package/package.json +1 -1
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* This file is generated by o-spreadsheet build tools. Do not edit it.
|
|
4
4
|
* @see https://github.com/odoo/o-spreadsheet
|
|
5
|
-
* @version 19.2.0-alpha.
|
|
6
|
-
* @date
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 19.2.0-alpha.2
|
|
6
|
+
* @date 2026-01-07T16:21:35.251Z
|
|
7
|
+
* @hash ac2fa3e
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
(function (exports, owl) {
|
|
@@ -10483,6 +10483,7 @@
|
|
|
10483
10483
|
case "dateIsAfter":
|
|
10484
10484
|
case "dateIsOnOrAfter":
|
|
10485
10485
|
case "dateIsOnOrBefore":
|
|
10486
|
+
case "top10":
|
|
10486
10487
|
rule.values = rule.values.map((v) => changeContentLocale(v));
|
|
10487
10488
|
return rule;
|
|
10488
10489
|
case "beginsWithText":
|
|
@@ -14632,6 +14633,7 @@
|
|
|
14632
14633
|
dateValue: _t("The value must be a date"),
|
|
14633
14634
|
validRange: _t("The value must be a valid range"),
|
|
14634
14635
|
validFormula: _t("The formula must be valid"),
|
|
14636
|
+
positiveNumber: _t("The value must be a positive number"),
|
|
14635
14637
|
},
|
|
14636
14638
|
Errors: {
|
|
14637
14639
|
["InvalidRange" /* CommandResult.InvalidRange */]: _t("The range is invalid."),
|
|
@@ -19609,17 +19611,41 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
19609
19611
|
const today = DateTime.now();
|
|
19610
19612
|
switch (dateValue) {
|
|
19611
19613
|
case "today":
|
|
19612
|
-
return jsDateToNumber(today);
|
|
19613
|
-
case "yesterday":
|
|
19614
|
-
|
|
19615
|
-
|
|
19616
|
-
|
|
19614
|
+
return Math.floor(jsDateToNumber(today));
|
|
19615
|
+
case "yesterday": {
|
|
19616
|
+
today.setDate(today.getDate() - 1);
|
|
19617
|
+
return Math.floor(jsDateToNumber(today));
|
|
19618
|
+
}
|
|
19619
|
+
case "tomorrow": {
|
|
19620
|
+
today.setDate(today.getDate() + 1);
|
|
19621
|
+
return Math.floor(jsDateToNumber(today));
|
|
19622
|
+
}
|
|
19617
19623
|
case "lastWeek":
|
|
19618
|
-
|
|
19619
|
-
|
|
19620
|
-
|
|
19624
|
+
today.setDate(today.getDate() - 6);
|
|
19625
|
+
return Math.floor(jsDateToNumber(today));
|
|
19626
|
+
case "lastMonth": {
|
|
19627
|
+
const lastMonth = today.getMonth() === 0 ? 11 : today.getMonth() - 1;
|
|
19628
|
+
const dateInLastMonth = new DateTime(today.getFullYear(), lastMonth, 1);
|
|
19629
|
+
if (today.getDate() > getDaysInMonth(dateInLastMonth)) {
|
|
19630
|
+
today.setDate(1);
|
|
19631
|
+
}
|
|
19632
|
+
else {
|
|
19633
|
+
today.setDate(today.getDate() + 1);
|
|
19634
|
+
today.setMonth(today.getMonth() - 1);
|
|
19635
|
+
}
|
|
19636
|
+
return Math.floor(jsDateToNumber(today));
|
|
19637
|
+
}
|
|
19621
19638
|
case "lastYear":
|
|
19622
|
-
|
|
19639
|
+
// Handle leap year case
|
|
19640
|
+
if (today.getMonth() === 1 && today.getDate() === 29) {
|
|
19641
|
+
today.setDate(28);
|
|
19642
|
+
today.setFullYear(today.getFullYear() - 1);
|
|
19643
|
+
}
|
|
19644
|
+
else {
|
|
19645
|
+
today.setDate(today.getDate() + 1);
|
|
19646
|
+
today.setFullYear(today.getFullYear() - 1);
|
|
19647
|
+
}
|
|
19648
|
+
return Math.floor(jsDateToNumber(today));
|
|
19623
19649
|
}
|
|
19624
19650
|
}
|
|
19625
19651
|
/** Get all the dates values of a criterion converted to numbers, converting date values such as "today" to actual dates */
|
|
@@ -31116,7 +31142,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
31116
31142
|
if (message.type === "CLIENT_JOINED" ||
|
|
31117
31143
|
message.type === "CLIENT_LEFT" ||
|
|
31118
31144
|
message.type === "CLIENT_MOVED") {
|
|
31119
|
-
this.transportService.sendMessage(message);
|
|
31145
|
+
await this.transportService.sendMessage(message);
|
|
31120
31146
|
}
|
|
31121
31147
|
// ignore all other messages
|
|
31122
31148
|
}
|
|
@@ -32290,7 +32316,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
32290
32316
|
}
|
|
32291
32317
|
delete this.clients[this.clientId];
|
|
32292
32318
|
this.transportService.leave(this.clientId);
|
|
32293
|
-
this.
|
|
32319
|
+
this.sendToTransport({
|
|
32294
32320
|
type: "CLIENT_LEFT",
|
|
32295
32321
|
clientId: this.clientId,
|
|
32296
32322
|
version: MESSAGE_VERSION,
|
|
@@ -32304,7 +32330,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
32304
32330
|
return;
|
|
32305
32331
|
}
|
|
32306
32332
|
const snapshotId = this.uuidGenerator.uuidv4();
|
|
32307
|
-
await this.
|
|
32333
|
+
await this.sendToTransport({
|
|
32308
32334
|
type: "SNAPSHOT",
|
|
32309
32335
|
nextRevisionId: snapshotId,
|
|
32310
32336
|
serverRevisionId: this.serverRevisionId,
|
|
@@ -32352,10 +32378,14 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
32352
32378
|
const type = currentPosition ? "CLIENT_MOVED" : "CLIENT_JOINED";
|
|
32353
32379
|
const client = this.getCurrentClient();
|
|
32354
32380
|
this.clients[this.clientId] = { ...client, position };
|
|
32355
|
-
this.
|
|
32381
|
+
this.sendToTransport({
|
|
32356
32382
|
type,
|
|
32357
32383
|
version: MESSAGE_VERSION,
|
|
32358
32384
|
client: { ...client, position },
|
|
32385
|
+
}).then(() => {
|
|
32386
|
+
if (this.pendingMessages.length > 0 && !this.waitingAck) {
|
|
32387
|
+
this.sendPendingMessage();
|
|
32388
|
+
}
|
|
32359
32389
|
});
|
|
32360
32390
|
}
|
|
32361
32391
|
/**
|
|
@@ -32436,7 +32466,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
32436
32466
|
if (client) {
|
|
32437
32467
|
const { position } = client;
|
|
32438
32468
|
if (position) {
|
|
32439
|
-
this.
|
|
32469
|
+
this.sendToTransport({
|
|
32440
32470
|
type: "CLIENT_MOVED",
|
|
32441
32471
|
version: MESSAGE_VERSION,
|
|
32442
32472
|
client: { ...client, position },
|
|
@@ -32457,6 +32487,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
32457
32487
|
}
|
|
32458
32488
|
this.sendPendingMessage();
|
|
32459
32489
|
}
|
|
32490
|
+
async sendToTransport(message) {
|
|
32491
|
+
// wrap in an async function to ensure it returns a promise
|
|
32492
|
+
return this.transportService.sendMessage(message);
|
|
32493
|
+
}
|
|
32460
32494
|
/**
|
|
32461
32495
|
* Send the next pending message
|
|
32462
32496
|
*/
|
|
@@ -32485,9 +32519,14 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
32485
32519
|
${JSON.stringify(message)}`);
|
|
32486
32520
|
}
|
|
32487
32521
|
this.waitingAck = true;
|
|
32488
|
-
this.
|
|
32522
|
+
this.sendToTransport({
|
|
32489
32523
|
...message,
|
|
32490
32524
|
serverRevisionId: this.serverRevisionId,
|
|
32525
|
+
}).catch((e) => {
|
|
32526
|
+
if (!(e instanceof ClientDisconnectedError)) {
|
|
32527
|
+
throw e.cause || e;
|
|
32528
|
+
}
|
|
32529
|
+
this.waitingAck = false;
|
|
32491
32530
|
});
|
|
32492
32531
|
}
|
|
32493
32532
|
acknowledge(message) {
|
|
@@ -33983,6 +34022,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
33983
34022
|
greaterThanOrEqual: "isGreaterOrEqualTo",
|
|
33984
34023
|
lessThan: "isLessThan",
|
|
33985
34024
|
lessThanOrEqual: "isLessOrEqualTo",
|
|
34025
|
+
top10: "top10",
|
|
33986
34026
|
};
|
|
33987
34027
|
/** Conversion map CF types in XLSX <=> Cf types in o_spreadsheet */
|
|
33988
34028
|
const CF_TYPE_CONVERSION_MAP = {
|
|
@@ -34523,6 +34563,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
34523
34563
|
const rule = cf.cfRules[0];
|
|
34524
34564
|
let operator;
|
|
34525
34565
|
const values = [];
|
|
34566
|
+
const cfAdditionalProperties = {};
|
|
34526
34567
|
if (rule.dxfId === undefined &&
|
|
34527
34568
|
!(rule.type === "colorScale" || rule.type === "iconSet" || rule.type === "dataBar"))
|
|
34528
34569
|
continue;
|
|
@@ -34531,7 +34572,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
34531
34572
|
case "containsErrors":
|
|
34532
34573
|
case "notContainsErrors":
|
|
34533
34574
|
case "duplicateValues":
|
|
34534
|
-
case "top10":
|
|
34535
34575
|
case "uniqueValues":
|
|
34536
34576
|
case "timePeriod":
|
|
34537
34577
|
// Not supported
|
|
@@ -34582,6 +34622,18 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
34582
34622
|
values.push(prefixFormulaWithEqual(rule.formula[1]));
|
|
34583
34623
|
}
|
|
34584
34624
|
break;
|
|
34625
|
+
case "top10":
|
|
34626
|
+
if (rule.rank === undefined)
|
|
34627
|
+
continue;
|
|
34628
|
+
operator = CF_OPERATOR_TYPE_CONVERSION_MAP[rule.type];
|
|
34629
|
+
values.push(rule.rank.toString());
|
|
34630
|
+
if (rule.percent) {
|
|
34631
|
+
cfAdditionalProperties.isPercent = true;
|
|
34632
|
+
}
|
|
34633
|
+
if (rule.bottom) {
|
|
34634
|
+
cfAdditionalProperties.isBottom = true;
|
|
34635
|
+
}
|
|
34636
|
+
break;
|
|
34585
34637
|
}
|
|
34586
34638
|
if (operator && rule.dxfId !== undefined) {
|
|
34587
34639
|
cfs.push({
|
|
@@ -34592,6 +34644,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
34592
34644
|
type: "CellIsRule",
|
|
34593
34645
|
operator: operator,
|
|
34594
34646
|
values: values,
|
|
34647
|
+
...cfAdditionalProperties,
|
|
34595
34648
|
style: convertStyle({ fontStyle: dxfs[rule.dxfId].font, fillStyle: dxfs[rule.dxfId].fill }, warningManager),
|
|
34596
34649
|
},
|
|
34597
34650
|
});
|
|
@@ -34810,6 +34863,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
34810
34863
|
return "greaterThanOrEqual";
|
|
34811
34864
|
case "dateIsOnOrBefore":
|
|
34812
34865
|
return "lessThanOrEqual";
|
|
34866
|
+
case "top10":
|
|
34867
|
+
return "top10";
|
|
34813
34868
|
}
|
|
34814
34869
|
}
|
|
34815
34870
|
// -------------------------------------
|
|
@@ -40211,7 +40266,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
40211
40266
|
return false;
|
|
40212
40267
|
}
|
|
40213
40268
|
if (["lastWeek", "lastMonth", "lastYear"].includes(criterion.dateValue)) {
|
|
40214
|
-
const today =
|
|
40269
|
+
const today = Math.floor(jsDateToNumber(DateTime.now()));
|
|
40215
40270
|
return isDateBetween(dateValue, today, criterionValue);
|
|
40216
40271
|
}
|
|
40217
40272
|
return areDatesSameDay(dateValue, criterionValue);
|
|
@@ -40593,15 +40648,20 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
40593
40648
|
getPreview: (criterion) => _t("Value one of: %s", criterion.values.join(", ")),
|
|
40594
40649
|
});
|
|
40595
40650
|
criterionEvaluatorRegistry.add("isValueInRange", {
|
|
40596
|
-
type: "
|
|
40597
|
-
|
|
40651
|
+
type: "isValueInRange",
|
|
40652
|
+
preComputeCriterion: (criterion, criterionRanges, getters) => {
|
|
40653
|
+
if (criterionRanges.length === 0) {
|
|
40654
|
+
return new Set();
|
|
40655
|
+
}
|
|
40656
|
+
const sheetId = criterionRanges[0].sheetId;
|
|
40657
|
+
const criterionValues = getters.getDataValidationRangeValues(sheetId, criterion);
|
|
40658
|
+
return new Set(criterionValues.map((value) => value.value.toString().toLowerCase()));
|
|
40659
|
+
},
|
|
40660
|
+
isValueValid: (value, criterion, valuesSet) => {
|
|
40598
40661
|
if (!value) {
|
|
40599
40662
|
return false;
|
|
40600
40663
|
}
|
|
40601
|
-
|
|
40602
|
-
return criterionValues
|
|
40603
|
-
.map((value) => value.value.toLowerCase())
|
|
40604
|
-
.includes(value.toString().toLowerCase());
|
|
40664
|
+
return valuesSet.has(value.toString().toLowerCase());
|
|
40605
40665
|
},
|
|
40606
40666
|
getErrorString: (criterion) => _t("The value must be a value in the range %s", String(criterion.values[0])),
|
|
40607
40667
|
isCriterionValueValid: (value) => rangeReference.test(value),
|
|
@@ -40678,6 +40738,67 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
40678
40738
|
name: _t("Is not empty"),
|
|
40679
40739
|
getPreview: () => _t("Is not empty"),
|
|
40680
40740
|
});
|
|
40741
|
+
criterionEvaluatorRegistry.add("top10", {
|
|
40742
|
+
type: "top10",
|
|
40743
|
+
preComputeCriterion: (criterion, criterionRanges, getters) => {
|
|
40744
|
+
let value = tryToNumber(criterion.values[0], DEFAULT_LOCALE);
|
|
40745
|
+
if (value === undefined || value <= 0) {
|
|
40746
|
+
return undefined;
|
|
40747
|
+
}
|
|
40748
|
+
const numberValues = [];
|
|
40749
|
+
for (const range of criterionRanges) {
|
|
40750
|
+
for (const value of getters.getRangeValues(range)) {
|
|
40751
|
+
if (typeof value === "number") {
|
|
40752
|
+
numberValues.push(value);
|
|
40753
|
+
}
|
|
40754
|
+
}
|
|
40755
|
+
}
|
|
40756
|
+
const sortedValues = numberValues.sort((a, b) => a - b);
|
|
40757
|
+
if (criterion.isPercent) {
|
|
40758
|
+
value = clip(value, 1, 100);
|
|
40759
|
+
}
|
|
40760
|
+
let index = 0;
|
|
40761
|
+
if (criterion.isBottom && !criterion.isPercent) {
|
|
40762
|
+
index = value - 1;
|
|
40763
|
+
}
|
|
40764
|
+
else if (criterion.isBottom && criterion.isPercent) {
|
|
40765
|
+
index = Math.floor((sortedValues.length * value) / 100) - 1;
|
|
40766
|
+
}
|
|
40767
|
+
else if (!criterion.isBottom && criterion.isPercent) {
|
|
40768
|
+
index = sortedValues.length - Math.floor((sortedValues.length * value) / 100);
|
|
40769
|
+
}
|
|
40770
|
+
else {
|
|
40771
|
+
index = sortedValues.length - value;
|
|
40772
|
+
}
|
|
40773
|
+
index = clip(index, 0, sortedValues.length - 1);
|
|
40774
|
+
return sortedValues[index];
|
|
40775
|
+
},
|
|
40776
|
+
isValueValid: (value, criterion, threshold) => {
|
|
40777
|
+
if (typeof value !== "number" || threshold === undefined) {
|
|
40778
|
+
return false;
|
|
40779
|
+
}
|
|
40780
|
+
return criterion.isBottom ? value <= threshold : value >= threshold;
|
|
40781
|
+
},
|
|
40782
|
+
getErrorString: (criterion) => {
|
|
40783
|
+
const args = {
|
|
40784
|
+
value: String(criterion.values[0]),
|
|
40785
|
+
percentSymbol: criterion.isPercent ? "%" : "",
|
|
40786
|
+
};
|
|
40787
|
+
return criterion.isBottom
|
|
40788
|
+
? _t("The value must be in bottom %(value)s%(percentSymbol)s", args)
|
|
40789
|
+
: _t("The value must be in top %(value)s%(percentSymbol)s", args);
|
|
40790
|
+
},
|
|
40791
|
+
isCriterionValueValid: (value) => checkValueIsPositiveNumber(value),
|
|
40792
|
+
criterionValueErrorString: DVTerms.CriterionError.positiveNumber,
|
|
40793
|
+
numberOfValues: () => 1,
|
|
40794
|
+
name: _t("Is in Top/Bottom ranking"),
|
|
40795
|
+
getPreview: (criterion) => {
|
|
40796
|
+
const args = { value: criterion.values[0], percentSymbol: criterion.isPercent ? "%" : "" };
|
|
40797
|
+
return criterion.isBottom
|
|
40798
|
+
? _t("Value is in bottom %(value)s%(percentSymbol)s", args)
|
|
40799
|
+
: _t("Value is in top %(value)s%(percentSymbol)s", args);
|
|
40800
|
+
},
|
|
40801
|
+
});
|
|
40681
40802
|
function getNumberCriterionlocalizedValues(criterion, locale) {
|
|
40682
40803
|
return criterion.values.map((value) => {
|
|
40683
40804
|
return value !== undefined
|
|
@@ -40699,6 +40820,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
40699
40820
|
const valueAsNumber = tryToNumber(value, DEFAULT_LOCALE);
|
|
40700
40821
|
return valueAsNumber !== undefined;
|
|
40701
40822
|
}
|
|
40823
|
+
function checkValueIsPositiveNumber(value) {
|
|
40824
|
+
const valueAsNumber = tryToNumber(value, DEFAULT_LOCALE);
|
|
40825
|
+
return valueAsNumber !== undefined && valueAsNumber > 0;
|
|
40826
|
+
}
|
|
40702
40827
|
|
|
40703
40828
|
// -----------------------------------------------------------------------------
|
|
40704
40829
|
// Constants
|
|
@@ -51073,6 +51198,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
51073
51198
|
break;
|
|
51074
51199
|
case "CellIsRule":
|
|
51075
51200
|
const formulas = cf.rule.values.map((value) => value.startsWith("=") ? compile(value) : undefined);
|
|
51201
|
+
const evaluator = criterionEvaluatorRegistry.get(cf.rule.operator);
|
|
51202
|
+
const criterion = { ...cf.rule, type: cf.rule.operator };
|
|
51203
|
+
const ranges = cf.ranges.map((xc) => this.getters.getRangeFromSheetXC(sheetId, xc));
|
|
51204
|
+
const preComputedCriterion = evaluator.preComputeCriterion?.(criterion, ranges, this.getters);
|
|
51076
51205
|
for (const ref of cf.ranges) {
|
|
51077
51206
|
const zone = this.getters.getRangeFromSheetXC(sheetId, ref).zone;
|
|
51078
51207
|
for (let row = zone.top; row <= zone.bottom; row++) {
|
|
@@ -51085,7 +51214,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
51085
51214
|
}
|
|
51086
51215
|
return value;
|
|
51087
51216
|
});
|
|
51088
|
-
if (this.getRuleResultForTarget(target, { ...cf.rule, values })) {
|
|
51217
|
+
if (this.getRuleResultForTarget(target, { ...cf.rule, values }, preComputedCriterion)) {
|
|
51089
51218
|
if (!computedStyle[col])
|
|
51090
51219
|
computedStyle[col] = [];
|
|
51091
51220
|
// we must combine all the properties of all the CF rules applied to the given cell
|
|
@@ -51248,7 +51377,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
51248
51377
|
}
|
|
51249
51378
|
}
|
|
51250
51379
|
}
|
|
51251
|
-
getRuleResultForTarget(target, rule) {
|
|
51380
|
+
getRuleResultForTarget(target, rule, preComputedCriterion) {
|
|
51252
51381
|
const cell = this.getters.getEvaluatedCell(target);
|
|
51253
51382
|
if (cell.type === CellValueType.error) {
|
|
51254
51383
|
return false;
|
|
@@ -51265,11 +51394,12 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
51265
51394
|
return false;
|
|
51266
51395
|
}
|
|
51267
51396
|
const evaluatedCriterion = {
|
|
51397
|
+
...rule,
|
|
51268
51398
|
type: rule.operator,
|
|
51269
51399
|
values: evaluatedCriterionValues.map(toScalar),
|
|
51270
51400
|
dateValue: rule.dateValue || "exactDate",
|
|
51271
51401
|
};
|
|
51272
|
-
return evaluator.isValueValid(cell.value ?? "", evaluatedCriterion,
|
|
51402
|
+
return evaluator.isValueValid(cell.value ?? "", evaluatedCriterion, preComputedCriterion);
|
|
51273
51403
|
}
|
|
51274
51404
|
}
|
|
51275
51405
|
|
|
@@ -51286,17 +51416,20 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
51286
51416
|
"isDataValidationInvalid",
|
|
51287
51417
|
];
|
|
51288
51418
|
validationResults = {};
|
|
51419
|
+
criterionPreComputeResult = {};
|
|
51289
51420
|
handle(cmd) {
|
|
51290
51421
|
if (invalidateEvaluationCommands.has(cmd.type) ||
|
|
51291
51422
|
cmd.type === "EVALUATE_CELLS" ||
|
|
51292
51423
|
(cmd.type === "UPDATE_CELL" && ("content" in cmd || "format" in cmd))) {
|
|
51293
51424
|
this.validationResults = {};
|
|
51425
|
+
this.criterionPreComputeResult = {};
|
|
51294
51426
|
return;
|
|
51295
51427
|
}
|
|
51296
51428
|
switch (cmd.type) {
|
|
51297
51429
|
case "ADD_DATA_VALIDATION_RULE":
|
|
51298
51430
|
case "REMOVE_DATA_VALIDATION_RULE":
|
|
51299
51431
|
delete this.validationResults[cmd.sheetId];
|
|
51432
|
+
delete this.criterionPreComputeResult[cmd.sheetId];
|
|
51300
51433
|
break;
|
|
51301
51434
|
}
|
|
51302
51435
|
}
|
|
@@ -51439,7 +51572,15 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
51439
51572
|
return undefined;
|
|
51440
51573
|
}
|
|
51441
51574
|
const evaluatedCriterion = { ...criterion, values: evaluatedCriterionValues.map(toScalar) };
|
|
51442
|
-
if (
|
|
51575
|
+
if (!this.criterionPreComputeResult[sheetId]) {
|
|
51576
|
+
this.criterionPreComputeResult[sheetId] = {};
|
|
51577
|
+
}
|
|
51578
|
+
let preComputedCriterion = this.criterionPreComputeResult[sheetId][rule.id];
|
|
51579
|
+
if (preComputedCriterion === undefined) {
|
|
51580
|
+
preComputedCriterion = evaluator.preComputeCriterion?.(rule.criterion, rule.ranges, this.getters);
|
|
51581
|
+
this.criterionPreComputeResult[sheetId][rule.id] = preComputedCriterion;
|
|
51582
|
+
}
|
|
51583
|
+
if (evaluator.isValueValid(cellValue, evaluatedCriterion, preComputedCriterion)) {
|
|
51443
51584
|
return undefined;
|
|
51444
51585
|
}
|
|
51445
51586
|
return evaluator.getErrorString(evaluatedCriterion, this.getters, sheetId);
|
|
@@ -57134,6 +57275,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
57134
57275
|
if (filterValue.type === "none")
|
|
57135
57276
|
continue;
|
|
57136
57277
|
const evaluator = criterionEvaluatorRegistry.get(filterValue.type);
|
|
57278
|
+
const preComputedCriterion = evaluator.preComputeCriterion?.(filterValue, [filter.filteredRange], this.getters);
|
|
57137
57279
|
const evaluatedCriterionValues = filterValue.values.map((value) => {
|
|
57138
57280
|
if (!value.startsWith("=")) {
|
|
57139
57281
|
return parseLiteral(value, DEFAULT_LOCALE);
|
|
@@ -57151,7 +57293,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
57151
57293
|
for (let row = filteredZone.top; row <= filteredZone.bottom; row++) {
|
|
57152
57294
|
const position = { sheetId, col: filter.col, row };
|
|
57153
57295
|
const value = this.getters.getEvaluatedCell(position).value ?? "";
|
|
57154
|
-
if (!evaluator.isValueValid(value, evaluatedCriterion,
|
|
57296
|
+
if (!evaluator.isValueValid(value, evaluatedCriterion, preComputedCriterion)) {
|
|
57155
57297
|
hiddenRows.add(row);
|
|
57156
57298
|
}
|
|
57157
57299
|
}
|
|
@@ -61278,6 +61420,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
61278
61420
|
case undefined:
|
|
61279
61421
|
throw new Error("dateValue should be defined");
|
|
61280
61422
|
}
|
|
61423
|
+
case "top10":
|
|
61424
|
+
return [];
|
|
61281
61425
|
}
|
|
61282
61426
|
}
|
|
61283
61427
|
function cellRuleTypeAttributes(rule) {
|
|
@@ -61310,6 +61454,14 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
61310
61454
|
case "dateIs":
|
|
61311
61455
|
case "customFormula":
|
|
61312
61456
|
return [["type", "expression"]];
|
|
61457
|
+
case "top10": {
|
|
61458
|
+
return [
|
|
61459
|
+
["type", "top10"],
|
|
61460
|
+
["rank", rule.values[0]],
|
|
61461
|
+
["percent", rule.isPercent ? "1" : "0"],
|
|
61462
|
+
["bottom", rule.isBottom ? "1" : "0"],
|
|
61463
|
+
];
|
|
61464
|
+
}
|
|
61313
61465
|
}
|
|
61314
61466
|
}
|
|
61315
61467
|
function addDataBarRule(cf, rule) {
|
|
@@ -65030,6 +65182,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
65030
65182
|
"dateIsAfter",
|
|
65031
65183
|
"dateIsOnOrBefore",
|
|
65032
65184
|
"dateIsOnOrAfter",
|
|
65185
|
+
"top10",
|
|
65033
65186
|
];
|
|
65034
65187
|
const availableConditionalFormatOperators = new Set(cfOperators);
|
|
65035
65188
|
|
|
@@ -73001,6 +73154,26 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
73001
73154
|
}
|
|
73002
73155
|
}
|
|
73003
73156
|
|
|
73157
|
+
class Top10CriterionForm extends CriterionForm {
|
|
73158
|
+
static template = "o-spreadsheet-Top10CriterionForm";
|
|
73159
|
+
static components = { CriterionInput };
|
|
73160
|
+
onValueChanged(value) {
|
|
73161
|
+
const criterion = deepCopy(this.props.criterion);
|
|
73162
|
+
criterion.values[0] = value;
|
|
73163
|
+
this.updateCriterion(criterion);
|
|
73164
|
+
}
|
|
73165
|
+
updateIsBottom(ev) {
|
|
73166
|
+
const criterion = deepCopy(this.props.criterion);
|
|
73167
|
+
criterion.isBottom = ev.target.value === "bottom";
|
|
73168
|
+
this.updateCriterion(criterion);
|
|
73169
|
+
}
|
|
73170
|
+
updateIsPercent(ev) {
|
|
73171
|
+
const criterion = deepCopy(this.props.criterion);
|
|
73172
|
+
criterion.isPercent = ev.target.value === "percent";
|
|
73173
|
+
this.updateCriterion(criterion);
|
|
73174
|
+
}
|
|
73175
|
+
}
|
|
73176
|
+
|
|
73004
73177
|
/**
|
|
73005
73178
|
* Start listening to pointer events and apply the given callbacks.
|
|
73006
73179
|
*
|
|
@@ -74170,6 +74343,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
74170
74343
|
text: 20,
|
|
74171
74344
|
number: 30,
|
|
74172
74345
|
date: 40,
|
|
74346
|
+
relative: 45,
|
|
74173
74347
|
misc: 50,
|
|
74174
74348
|
};
|
|
74175
74349
|
const criterionComponentRegistry = new Registry$1();
|
|
@@ -74347,6 +74521,12 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
74347
74521
|
category: "misc",
|
|
74348
74522
|
sequence: 6,
|
|
74349
74523
|
});
|
|
74524
|
+
criterionComponentRegistry.add("top10", {
|
|
74525
|
+
type: "top10",
|
|
74526
|
+
component: Top10CriterionForm,
|
|
74527
|
+
category: "relative",
|
|
74528
|
+
sequence: 7,
|
|
74529
|
+
});
|
|
74350
74530
|
function getCriterionMenuItems(callback, availableTypes) {
|
|
74351
74531
|
const items = criterionComponentRegistry
|
|
74352
74532
|
.getAll()
|
|
@@ -75977,7 +76157,17 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
75977
76157
|
// Side panel
|
|
75978
76158
|
//------------------------------------------------------------------------------
|
|
75979
76159
|
const OPEN_CF_SIDEPANEL_ACTION = (env) => {
|
|
75980
|
-
|
|
76160
|
+
const sheetId = env.model.getters.getActiveSheetId();
|
|
76161
|
+
const zones = env.model.getters.getSelectedZones();
|
|
76162
|
+
const rules = env.model.getters.getConditionalFormats(sheetId);
|
|
76163
|
+
const ruleIds = env.model.getters.getRulesSelection(sheetId, zones);
|
|
76164
|
+
if (ruleIds.length === 1) {
|
|
76165
|
+
return env.openSidePanel("ConditionalFormattingEditor", {
|
|
76166
|
+
cf: rules.find((r) => r.id === ruleIds[0]),
|
|
76167
|
+
isNewCf: false,
|
|
76168
|
+
});
|
|
76169
|
+
}
|
|
76170
|
+
return env.openSidePanel("ConditionalFormatting");
|
|
75981
76171
|
};
|
|
75982
76172
|
const INSERT_LINK = (env) => {
|
|
75983
76173
|
const { col, row } = env.model.getters.getActivePosition();
|
|
@@ -76975,12 +77165,12 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
76975
77165
|
const zones = env.model.getters.getSelectedZones();
|
|
76976
77166
|
const sheetId = env.model.getters.getActiveSheetId();
|
|
76977
77167
|
const ranges = zones.map((zone) => env.model.getters.getRangeDataFromZone(sheetId, zone));
|
|
76978
|
-
const
|
|
77168
|
+
const ruleId = env.model.uuidGenerator.smallUuid();
|
|
76979
77169
|
env.model.dispatch("ADD_DATA_VALIDATION_RULE", {
|
|
76980
77170
|
ranges,
|
|
76981
77171
|
sheetId,
|
|
76982
77172
|
rule: {
|
|
76983
|
-
id:
|
|
77173
|
+
id: ruleId,
|
|
76984
77174
|
criterion: {
|
|
76985
77175
|
type: "isValueInList",
|
|
76986
77176
|
values: [],
|
|
@@ -76988,16 +77178,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
76988
77178
|
},
|
|
76989
77179
|
},
|
|
76990
77180
|
});
|
|
76991
|
-
const rule = env.model.getters.getDataValidationRule(sheetId,
|
|
77181
|
+
const rule = env.model.getters.getDataValidationRule(sheetId, ruleId);
|
|
76992
77182
|
if (!rule) {
|
|
76993
77183
|
return;
|
|
76994
77184
|
}
|
|
76995
|
-
env.openSidePanel("DataValidationEditor", {
|
|
76996
|
-
rule: localizeDataValidationRule(rule, env.model.getters.getLocale()),
|
|
76997
|
-
onExit: () => {
|
|
76998
|
-
env.replaceSidePanel("DataValidation", "DataValidationEditor");
|
|
76999
|
-
},
|
|
77000
|
-
});
|
|
77185
|
+
env.openSidePanel("DataValidationEditor", { ruleId });
|
|
77001
77186
|
},
|
|
77002
77187
|
isEnabled: (env) => !env.isSmall,
|
|
77003
77188
|
icon: "o-spreadsheet-Icon.INSERT_DROPDOWN",
|
|
@@ -80272,7 +80457,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
80272
80457
|
onGridMoved: Function,
|
|
80273
80458
|
gridOverlayDimensions: String,
|
|
80274
80459
|
slots: { type: Object, optional: true },
|
|
80275
|
-
getGridSize: Function,
|
|
80276
80460
|
};
|
|
80277
80461
|
static components = {
|
|
80278
80462
|
FiguresContainer,
|
|
@@ -80291,14 +80475,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
80291
80475
|
setup() {
|
|
80292
80476
|
useCellHovered(this.env, this.gridOverlay);
|
|
80293
80477
|
const resizeObserver = new ResizeObserver(() => {
|
|
80294
|
-
|
|
80295
|
-
const { width, height } = this.props.getGridSize();
|
|
80296
|
-
this.props.onGridResized({
|
|
80297
|
-
x: boundingRect.left,
|
|
80298
|
-
y: boundingRect.top,
|
|
80299
|
-
height: height,
|
|
80300
|
-
width: width,
|
|
80301
|
-
});
|
|
80478
|
+
this.props.onGridResized();
|
|
80302
80479
|
});
|
|
80303
80480
|
owl.onMounted(() => {
|
|
80304
80481
|
resizeObserver.observe(this.gridOverlayEl);
|
|
@@ -85457,210 +85634,36 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
85457
85634
|
}
|
|
85458
85635
|
}
|
|
85459
85636
|
|
|
85460
|
-
|
|
85461
|
-
|
|
85462
|
-
useHighlights({
|
|
85463
|
-
get highlights() {
|
|
85464
|
-
return hoverState.hovered ? highlightProvider.highlights : [];
|
|
85465
|
-
},
|
|
85466
|
-
});
|
|
85467
|
-
}
|
|
85468
|
-
function useHighlights(highlightProvider) {
|
|
85469
|
-
const stores = useStoreProvider();
|
|
85470
|
-
const store = useLocalStore(HighlightStore);
|
|
85471
|
-
owl.onMounted(() => {
|
|
85472
|
-
store.register(highlightProvider);
|
|
85473
|
-
});
|
|
85474
|
-
let currentHighlights = highlightProvider.highlights;
|
|
85475
|
-
owl.useEffect((highlights) => {
|
|
85476
|
-
if (!deepEquals(highlights, currentHighlights)) {
|
|
85477
|
-
currentHighlights = highlights;
|
|
85478
|
-
stores.trigger("store-updated");
|
|
85479
|
-
}
|
|
85480
|
-
}, () => [highlightProvider.highlights]);
|
|
85481
|
-
}
|
|
85482
|
-
|
|
85483
|
-
class ConditionalFormatPreview extends owl.Component {
|
|
85484
|
-
static template = "o-spreadsheet-ConditionalFormatPreview";
|
|
85485
|
-
icons = ICONS;
|
|
85486
|
-
ref = owl.useRef("cfPreview");
|
|
85487
|
-
setup() {
|
|
85488
|
-
useHighlightsOnHover(this.ref, this);
|
|
85489
|
-
}
|
|
85490
|
-
getPreviewImageStyle() {
|
|
85491
|
-
const rule = this.props.conditionalFormat.rule;
|
|
85492
|
-
if (rule.type === "CellIsRule") {
|
|
85493
|
-
return cssPropertiesToCss(cellStyleToCss(rule.style));
|
|
85494
|
-
}
|
|
85495
|
-
else if (rule.type === "ColorScaleRule") {
|
|
85496
|
-
const minColor = colorNumberToHex(rule.minimum.color);
|
|
85497
|
-
const midColor = rule.midpoint ? colorNumberToHex(rule.midpoint.color) : null;
|
|
85498
|
-
const maxColor = colorNumberToHex(rule.maximum.color);
|
|
85499
|
-
const baseString = "background-image: linear-gradient(to right, ";
|
|
85500
|
-
return midColor
|
|
85501
|
-
? baseString + minColor + ", " + midColor + ", " + maxColor + ")"
|
|
85502
|
-
: baseString + minColor + ", " + maxColor + ")";
|
|
85503
|
-
}
|
|
85504
|
-
else if (rule.type === "DataBarRule") {
|
|
85505
|
-
const barColor = colorNumberToHex(rule.color);
|
|
85506
|
-
const gradient = `background-image: linear-gradient(to right, ${barColor} 50%, white 50%)`;
|
|
85507
|
-
return `${gradient}; color: ${TEXT_BODY};`;
|
|
85508
|
-
}
|
|
85509
|
-
return "";
|
|
85510
|
-
}
|
|
85511
|
-
getDescription() {
|
|
85512
|
-
const cf = this.props.conditionalFormat;
|
|
85513
|
-
switch (cf.rule.type) {
|
|
85514
|
-
case "CellIsRule":
|
|
85515
|
-
return criterionEvaluatorRegistry
|
|
85516
|
-
.get(cf.rule.operator)
|
|
85517
|
-
.getPreview({ ...cf.rule, type: cf.rule.operator }, this.env.model.getters);
|
|
85518
|
-
case "ColorScaleRule":
|
|
85519
|
-
return CfTerms.ColorScale;
|
|
85520
|
-
case "IconSetRule":
|
|
85521
|
-
return CfTerms.IconSet;
|
|
85522
|
-
case "DataBarRule":
|
|
85523
|
-
return CfTerms.DataBar;
|
|
85524
|
-
}
|
|
85525
|
-
}
|
|
85526
|
-
deleteConditionalFormat() {
|
|
85527
|
-
this.env.model.dispatch("REMOVE_CONDITIONAL_FORMAT", {
|
|
85528
|
-
id: this.props.conditionalFormat.id,
|
|
85529
|
-
sheetId: this.env.model.getters.getActiveSheetId(),
|
|
85530
|
-
});
|
|
85531
|
-
}
|
|
85532
|
-
onMouseDown(event) {
|
|
85533
|
-
this.props.onMouseDown(event);
|
|
85534
|
-
}
|
|
85535
|
-
get highlights() {
|
|
85536
|
-
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
85537
|
-
return this.props.conditionalFormat.ranges.map((range) => ({
|
|
85538
|
-
range: this.env.model.getters.getRangeFromSheetXC(sheetId, range),
|
|
85539
|
-
color: HIGHLIGHT_COLOR,
|
|
85540
|
-
fillAlpha: 0.06,
|
|
85541
|
-
}));
|
|
85542
|
-
}
|
|
85543
|
-
}
|
|
85544
|
-
ConditionalFormatPreview.props = {
|
|
85545
|
-
conditionalFormat: Object,
|
|
85546
|
-
onPreviewClick: Function,
|
|
85547
|
-
onMouseDown: Function,
|
|
85548
|
-
class: String,
|
|
85549
|
-
};
|
|
85550
|
-
|
|
85551
|
-
class ConditionalFormatPreviewList extends owl.Component {
|
|
85552
|
-
static template = "o-spreadsheet-ConditionalFormatPreviewList";
|
|
85553
|
-
static props = {
|
|
85554
|
-
conditionalFormats: Array,
|
|
85555
|
-
onPreviewClick: Function,
|
|
85556
|
-
onAddConditionalFormat: Function,
|
|
85557
|
-
};
|
|
85558
|
-
static components = { ConditionalFormatPreview };
|
|
85559
|
-
icons = ICONS;
|
|
85560
|
-
dragAndDrop = useDragAndDropListItems();
|
|
85561
|
-
cfListRef = owl.useRef("cfList");
|
|
85562
|
-
setup() {
|
|
85563
|
-
owl.onWillUpdateProps((nextProps) => {
|
|
85564
|
-
if (!deepEquals(this.props.conditionalFormats, nextProps.conditionalFormats)) {
|
|
85565
|
-
this.dragAndDrop.cancel();
|
|
85566
|
-
}
|
|
85567
|
-
});
|
|
85568
|
-
}
|
|
85569
|
-
getPreviewDivStyle(cf) {
|
|
85570
|
-
return this.dragAndDrop.itemsStyle[cf.id] || "";
|
|
85571
|
-
}
|
|
85572
|
-
onPreviewMouseDown(cf, event) {
|
|
85573
|
-
if (event.button !== 0)
|
|
85574
|
-
return;
|
|
85575
|
-
const previewRects = Array.from(this.cfListRef.el.children).map((previewEl) => getBoundingRectAsPOJO(previewEl));
|
|
85576
|
-
const items = this.props.conditionalFormats.map((cf, index) => ({
|
|
85577
|
-
id: cf.id,
|
|
85578
|
-
size: previewRects[index].height,
|
|
85579
|
-
position: previewRects[index].y,
|
|
85580
|
-
}));
|
|
85581
|
-
this.dragAndDrop.start("vertical", {
|
|
85582
|
-
draggedItemId: cf.id,
|
|
85583
|
-
initialMousePosition: event.clientY,
|
|
85584
|
-
items: items,
|
|
85585
|
-
scrollableContainerEl: this.cfListRef.el,
|
|
85586
|
-
onDragEnd: (cfId, finalIndex) => this.onDragEnd(cfId, finalIndex),
|
|
85587
|
-
});
|
|
85588
|
-
}
|
|
85589
|
-
onDragEnd(cfId, finalIndex) {
|
|
85590
|
-
const originalIndex = this.props.conditionalFormats.findIndex((sheet) => sheet.id === cfId);
|
|
85591
|
-
const delta = originalIndex - finalIndex;
|
|
85592
|
-
if (delta !== 0) {
|
|
85593
|
-
this.env.model.dispatch("CHANGE_CONDITIONAL_FORMAT_PRIORITY", {
|
|
85594
|
-
cfId,
|
|
85595
|
-
delta,
|
|
85596
|
-
sheetId: this.env.model.getters.getActiveSheetId(),
|
|
85597
|
-
});
|
|
85598
|
-
}
|
|
85599
|
-
}
|
|
85600
|
-
}
|
|
85601
|
-
|
|
85602
|
-
class ConditionalFormattingEditor extends owl.Component {
|
|
85603
|
-
static template = "o-spreadsheet-ConditionalFormattingEditor";
|
|
85604
|
-
static props = {
|
|
85605
|
-
editedCf: Object,
|
|
85606
|
-
onCancel: Function,
|
|
85607
|
-
onExit: Function,
|
|
85608
|
-
isNewCf: Boolean,
|
|
85609
|
-
};
|
|
85610
|
-
static components = {
|
|
85611
|
-
SelectionInput,
|
|
85612
|
-
IconPicker,
|
|
85613
|
-
ColorPickerWidget,
|
|
85614
|
-
ConditionalFormatPreviewList,
|
|
85615
|
-
Section,
|
|
85616
|
-
RoundColorPicker,
|
|
85617
|
-
StandaloneComposer,
|
|
85618
|
-
BadgeSelection,
|
|
85619
|
-
ValidationMessages,
|
|
85620
|
-
SelectMenu,
|
|
85621
|
-
};
|
|
85637
|
+
class ConditionalFormattingEditorStore extends SpreadsheetStore {
|
|
85638
|
+
mutators = ["updateConditionalFormat", "closeMenus"];
|
|
85622
85639
|
icons = ICONS;
|
|
85623
85640
|
iconSets = ICON_SETS;
|
|
85624
|
-
getTextDecoration = getTextDecoration;
|
|
85625
|
-
colorNumberToHex = colorNumberToHex;
|
|
85626
85641
|
state;
|
|
85627
|
-
|
|
85642
|
+
cfId;
|
|
85643
|
+
constructor(get, cf, isNewCf) {
|
|
85644
|
+
super(get);
|
|
85645
|
+
this.cfId = cf.id;
|
|
85628
85646
|
this.state = owl.useState({
|
|
85629
85647
|
errors: [],
|
|
85630
|
-
currentCFType:
|
|
85631
|
-
ranges:
|
|
85648
|
+
currentCFType: cf.rule.type,
|
|
85649
|
+
ranges: cf.ranges,
|
|
85632
85650
|
rules: this.getDefaultRules(),
|
|
85633
|
-
hasEditedCf:
|
|
85651
|
+
hasEditedCf: isNewCf,
|
|
85634
85652
|
});
|
|
85635
|
-
switch (
|
|
85653
|
+
switch (cf.rule.type) {
|
|
85636
85654
|
case "CellIsRule":
|
|
85637
|
-
this.state.rules.cellIs =
|
|
85655
|
+
this.state.rules.cellIs = cf.rule;
|
|
85638
85656
|
break;
|
|
85639
85657
|
case "ColorScaleRule":
|
|
85640
|
-
this.state.rules.colorScale =
|
|
85658
|
+
this.state.rules.colorScale = cf.rule;
|
|
85641
85659
|
break;
|
|
85642
85660
|
case "IconSetRule":
|
|
85643
|
-
this.state.rules.iconSet =
|
|
85661
|
+
this.state.rules.iconSet = cf.rule;
|
|
85644
85662
|
break;
|
|
85645
85663
|
case "DataBarRule":
|
|
85646
|
-
this.state.rules.dataBar =
|
|
85664
|
+
this.state.rules.dataBar = cf.rule;
|
|
85647
85665
|
break;
|
|
85648
85666
|
}
|
|
85649
|
-
owl.useExternalListener(window, "click", this.closeMenus);
|
|
85650
|
-
}
|
|
85651
|
-
get isRangeValid() {
|
|
85652
|
-
return this.state.errors.includes("EmptyRange" /* CommandResult.EmptyRange */);
|
|
85653
|
-
}
|
|
85654
|
-
get errorMessages() {
|
|
85655
|
-
return this.state.errors.map((error) => CfTerms.Errors[error] || CfTerms.Errors.Unexpected);
|
|
85656
|
-
}
|
|
85657
|
-
get cfTypesValues() {
|
|
85658
|
-
return [
|
|
85659
|
-
{ value: "CellIsRule", label: _t("Single color") },
|
|
85660
|
-
{ value: "ColorScaleRule", label: _t("Color scale") },
|
|
85661
|
-
{ value: "IconSetRule", label: _t("Icon set") },
|
|
85662
|
-
{ value: "DataBarRule", label: _t("Data bar") },
|
|
85663
|
-
];
|
|
85664
85667
|
}
|
|
85665
85668
|
updateConditionalFormat(newCf) {
|
|
85666
85669
|
const ranges = newCf.ranges || this.state.ranges;
|
|
@@ -85669,17 +85672,17 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
85669
85672
|
if (!newCf.suppressErrors) {
|
|
85670
85673
|
this.state.errors = ["InvalidRange" /* CommandResult.InvalidRange */];
|
|
85671
85674
|
}
|
|
85672
|
-
return
|
|
85675
|
+
return;
|
|
85673
85676
|
}
|
|
85674
|
-
const sheetId = this.
|
|
85675
|
-
const locale = this.
|
|
85677
|
+
const sheetId = this.model.getters.getActiveSheetId();
|
|
85678
|
+
const locale = this.model.getters.getLocale();
|
|
85676
85679
|
const rule = newCf.rule || this.getEditedRule(this.state.currentCFType);
|
|
85677
|
-
const result = this.
|
|
85680
|
+
const result = this.model.dispatch("ADD_CONDITIONAL_FORMAT", {
|
|
85678
85681
|
cf: {
|
|
85682
|
+
id: this.cfId,
|
|
85679
85683
|
rule: canonicalizeCFRule(rule, locale),
|
|
85680
|
-
id: this.props.editedCf.id,
|
|
85681
85684
|
},
|
|
85682
|
-
ranges: ranges.map((xc) => this.
|
|
85685
|
+
ranges: ranges.map((xc) => this.model.getters.getRangeDataFromXc(sheetId, xc)),
|
|
85683
85686
|
sheetId,
|
|
85684
85687
|
});
|
|
85685
85688
|
if (result.isSuccessful) {
|
|
@@ -85689,71 +85692,18 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
85689
85692
|
if (!newCf.suppressErrors) {
|
|
85690
85693
|
this.state.errors = reasons;
|
|
85691
85694
|
}
|
|
85692
|
-
return reasons;
|
|
85693
85695
|
}
|
|
85694
|
-
|
|
85695
|
-
|
|
85696
|
-
case "CellIsRule":
|
|
85697
|
-
return this.state.rules.cellIs;
|
|
85698
|
-
case "ColorScaleRule":
|
|
85699
|
-
return this.state.rules.colorScale;
|
|
85700
|
-
case "IconSetRule":
|
|
85701
|
-
return this.state.rules.iconSet;
|
|
85702
|
-
case "DataBarRule":
|
|
85703
|
-
return this.state.rules.dataBar;
|
|
85704
|
-
}
|
|
85696
|
+
get isRangeValid() {
|
|
85697
|
+
return this.state.errors.includes("EmptyRange" /* CommandResult.EmptyRange */);
|
|
85705
85698
|
}
|
|
85706
|
-
|
|
85707
|
-
|
|
85708
|
-
if (result.length === 0) {
|
|
85709
|
-
this.props.onExit();
|
|
85710
|
-
}
|
|
85699
|
+
get errorMessages() {
|
|
85700
|
+
return this.state.errors.map((error) => CfTerms.Errors[error] || CfTerms.Errors.Unexpected);
|
|
85711
85701
|
}
|
|
85712
|
-
|
|
85713
|
-
|
|
85714
|
-
this.props.onCancel();
|
|
85715
|
-
}
|
|
85716
|
-
else {
|
|
85717
|
-
this.props.onExit();
|
|
85718
|
-
}
|
|
85702
|
+
onRangeUpdate(ranges) {
|
|
85703
|
+
this.state.ranges = ranges;
|
|
85719
85704
|
}
|
|
85720
|
-
|
|
85721
|
-
|
|
85722
|
-
cellIs: {
|
|
85723
|
-
type: "CellIsRule",
|
|
85724
|
-
operator: "isNotEmpty",
|
|
85725
|
-
values: [],
|
|
85726
|
-
style: { fillColor: "#b6d7a8" },
|
|
85727
|
-
},
|
|
85728
|
-
colorScale: {
|
|
85729
|
-
type: "ColorScaleRule",
|
|
85730
|
-
minimum: { type: "value", color: hexaToInt("EFF7FF") },
|
|
85731
|
-
midpoint: undefined,
|
|
85732
|
-
maximum: { type: "value", color: 0x6aa84f },
|
|
85733
|
-
},
|
|
85734
|
-
iconSet: {
|
|
85735
|
-
type: "IconSetRule",
|
|
85736
|
-
icons: {
|
|
85737
|
-
upper: "arrowGood",
|
|
85738
|
-
middle: "arrowNeutral",
|
|
85739
|
-
lower: "arrowBad",
|
|
85740
|
-
},
|
|
85741
|
-
upperInflectionPoint: {
|
|
85742
|
-
type: "percentage",
|
|
85743
|
-
value: "66",
|
|
85744
|
-
operator: "gt",
|
|
85745
|
-
},
|
|
85746
|
-
lowerInflectionPoint: {
|
|
85747
|
-
type: "percentage",
|
|
85748
|
-
value: "33",
|
|
85749
|
-
operator: "gt",
|
|
85750
|
-
},
|
|
85751
|
-
},
|
|
85752
|
-
dataBar: {
|
|
85753
|
-
type: "DataBarRule",
|
|
85754
|
-
color: 0xd9ead3,
|
|
85755
|
-
},
|
|
85756
|
-
};
|
|
85705
|
+
onRangeConfirmed() {
|
|
85706
|
+
this.updateConditionalFormat({ ranges: this.state.ranges });
|
|
85757
85707
|
}
|
|
85758
85708
|
changeRuleType(ruleType) {
|
|
85759
85709
|
if (this.state.currentCFType === ruleType) {
|
|
@@ -85763,34 +85713,45 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
85763
85713
|
this.state.currentCFType = ruleType;
|
|
85764
85714
|
this.updateConditionalFormat({ rule: this.getEditedRule(ruleType), suppressErrors: true });
|
|
85765
85715
|
}
|
|
85766
|
-
|
|
85767
|
-
|
|
85768
|
-
|
|
85769
|
-
|
|
85770
|
-
|
|
85771
|
-
|
|
85772
|
-
|
|
85773
|
-
|
|
85774
|
-
|
|
85775
|
-
|
|
85776
|
-
const isSelected = this.state.openedMenu === menu;
|
|
85777
|
-
this.closeMenus();
|
|
85778
|
-
if (!isSelected) {
|
|
85779
|
-
this.state.openedMenu = menu;
|
|
85716
|
+
getEditedRule(ruleType) {
|
|
85717
|
+
switch (ruleType) {
|
|
85718
|
+
case "CellIsRule":
|
|
85719
|
+
return this.state.rules.cellIs;
|
|
85720
|
+
case "ColorScaleRule":
|
|
85721
|
+
return this.state.rules.colorScale;
|
|
85722
|
+
case "IconSetRule":
|
|
85723
|
+
return this.state.rules.iconSet;
|
|
85724
|
+
case "DataBarRule":
|
|
85725
|
+
return this.state.rules.dataBar;
|
|
85780
85726
|
}
|
|
85781
85727
|
}
|
|
85782
|
-
closeMenus() {
|
|
85783
|
-
this.state.openedMenu = undefined;
|
|
85784
|
-
}
|
|
85785
85728
|
/*****************************************************************************
|
|
85786
85729
|
* Cell Is Rule
|
|
85787
85730
|
****************************************************************************/
|
|
85788
|
-
get
|
|
85789
|
-
return (
|
|
85790
|
-
|
|
85731
|
+
get cfCriterionMenuItems() {
|
|
85732
|
+
return getCriterionMenuItems((type) => this.editOperator(type), availableConditionalFormatOperators);
|
|
85733
|
+
}
|
|
85734
|
+
get selectedCriterionName() {
|
|
85735
|
+
return criterionEvaluatorRegistry.get(this.state.rules.cellIs.operator).name;
|
|
85736
|
+
}
|
|
85737
|
+
get criterionComponent() {
|
|
85738
|
+
return criterionComponentRegistry.get(this.state.rules.cellIs.operator).component;
|
|
85791
85739
|
}
|
|
85792
|
-
get
|
|
85793
|
-
return
|
|
85740
|
+
get genericCriterion() {
|
|
85741
|
+
return {
|
|
85742
|
+
...this.state.rules.cellIs,
|
|
85743
|
+
type: this.state.rules.cellIs.operator,
|
|
85744
|
+
};
|
|
85745
|
+
}
|
|
85746
|
+
onRuleValuesChanged(criterion) {
|
|
85747
|
+
const newRule = {
|
|
85748
|
+
...criterion,
|
|
85749
|
+
operator: criterion.type,
|
|
85750
|
+
type: "CellIsRule",
|
|
85751
|
+
style: this.state.rules.cellIs.style,
|
|
85752
|
+
};
|
|
85753
|
+
this.state.rules.cellIs = newRule;
|
|
85754
|
+
this.updateConditionalFormat({ rule: newRule });
|
|
85794
85755
|
}
|
|
85795
85756
|
toggleStyle(tool) {
|
|
85796
85757
|
const style = this.state.rules.cellIs.style;
|
|
@@ -85798,18 +85759,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
85798
85759
|
this.updateConditionalFormat({ rule: this.state.rules.cellIs });
|
|
85799
85760
|
this.closeMenus();
|
|
85800
85761
|
}
|
|
85801
|
-
onKeydown(event) {
|
|
85802
|
-
if (event.key === "F4") {
|
|
85803
|
-
const target = event.target;
|
|
85804
|
-
const update = cycleFixedReference({ start: target.selectionStart ?? 0, end: target.selectionEnd ?? 0 }, target.value, this.env.model.getters.getLocale());
|
|
85805
|
-
if (!update) {
|
|
85806
|
-
return;
|
|
85807
|
-
}
|
|
85808
|
-
target.value = update.content;
|
|
85809
|
-
target.setSelectionRange(update.selection.start, update.selection.end);
|
|
85810
|
-
target.dispatchEvent(new Event("input"));
|
|
85811
|
-
}
|
|
85812
|
-
}
|
|
85813
85762
|
setColor(target, color) {
|
|
85814
85763
|
this.state.rules.cellIs.style[target] = color;
|
|
85815
85764
|
this.updateConditionalFormat({ rule: this.state.rules.cellIs });
|
|
@@ -85823,62 +85772,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
85823
85772
|
this.updateConditionalFormat({ rule: this.state.rules.cellIs, suppressErrors: true });
|
|
85824
85773
|
this.closeMenus();
|
|
85825
85774
|
}
|
|
85826
|
-
get cfCriterionMenuItems() {
|
|
85827
|
-
return getCriterionMenuItems((type) => this.editOperator(type), availableConditionalFormatOperators);
|
|
85828
|
-
}
|
|
85829
|
-
get selectedCriterionName() {
|
|
85830
|
-
return criterionEvaluatorRegistry.get(this.state.rules.cellIs.operator).name;
|
|
85831
|
-
}
|
|
85832
|
-
get criterionComponent() {
|
|
85833
|
-
return criterionComponentRegistry.get(this.state.rules.cellIs.operator).component;
|
|
85834
|
-
}
|
|
85835
|
-
get genericCriterion() {
|
|
85836
|
-
return {
|
|
85837
|
-
type: this.state.rules.cellIs.operator,
|
|
85838
|
-
values: this.state.rules.cellIs.values,
|
|
85839
|
-
dateValue: this.state.rules.cellIs.dateValue,
|
|
85840
|
-
};
|
|
85841
|
-
}
|
|
85842
|
-
onRuleValuesChanged(rule) {
|
|
85843
|
-
this.state.rules.cellIs.values = rule.values;
|
|
85844
|
-
this.state.rules.cellIs.dateValue = rule.dateValue;
|
|
85845
|
-
this.updateConditionalFormat({
|
|
85846
|
-
rule: { ...this.state.rules.cellIs, values: rule.values, dateValue: rule.dateValue },
|
|
85847
|
-
});
|
|
85848
|
-
}
|
|
85849
85775
|
/*****************************************************************************
|
|
85850
85776
|
* Color Scale Rule
|
|
85851
85777
|
****************************************************************************/
|
|
85852
|
-
|
|
85853
|
-
switch (threshold) {
|
|
85854
|
-
case "minimum":
|
|
85855
|
-
return (this.state.errors.includes("MinInvalidFormula" /* CommandResult.MinInvalidFormula */) ||
|
|
85856
|
-
this.state.errors.includes("MinBiggerThanMid" /* CommandResult.MinBiggerThanMid */) ||
|
|
85857
|
-
this.state.errors.includes("MinBiggerThanMax" /* CommandResult.MinBiggerThanMax */) ||
|
|
85858
|
-
this.state.errors.includes("MinNaN" /* CommandResult.MinNaN */));
|
|
85859
|
-
case "midpoint":
|
|
85860
|
-
return (this.state.errors.includes("MidInvalidFormula" /* CommandResult.MidInvalidFormula */) ||
|
|
85861
|
-
this.state.errors.includes("MidNaN" /* CommandResult.MidNaN */) ||
|
|
85862
|
-
this.state.errors.includes("MidBiggerThanMax" /* CommandResult.MidBiggerThanMax */));
|
|
85863
|
-
case "maximum":
|
|
85864
|
-
return (this.state.errors.includes("MaxInvalidFormula" /* CommandResult.MaxInvalidFormula */) ||
|
|
85865
|
-
this.state.errors.includes("MaxNaN" /* CommandResult.MaxNaN */));
|
|
85866
|
-
default:
|
|
85867
|
-
return false;
|
|
85868
|
-
}
|
|
85869
|
-
}
|
|
85870
|
-
setColorScaleColor(target, color) {
|
|
85871
|
-
if (!isColorValid(color)) {
|
|
85872
|
-
return;
|
|
85873
|
-
}
|
|
85874
|
-
const point = this.state.rules.colorScale[target];
|
|
85875
|
-
if (point) {
|
|
85876
|
-
point.color = colorToNumber(color);
|
|
85877
|
-
}
|
|
85878
|
-
this.updateConditionalFormat({ rule: this.state.rules.colorScale });
|
|
85879
|
-
this.closeMenus();
|
|
85880
|
-
}
|
|
85881
|
-
getColorScalePreviewStyle() {
|
|
85778
|
+
get previewGradient() {
|
|
85882
85779
|
const rule = this.state.rules.colorScale;
|
|
85883
85780
|
const minColor = colorNumberToHex(rule.minimum.color);
|
|
85884
85781
|
const midColor = colorNumberToHex(rule.midpoint?.color || DEFAULT_COLOR_SCALE_MIDPOINT_COLOR);
|
|
@@ -85892,13 +85789,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
85892
85789
|
color: "#000",
|
|
85893
85790
|
});
|
|
85894
85791
|
}
|
|
85895
|
-
|
|
85896
|
-
return threshold
|
|
85897
|
-
? colorNumberToHex(threshold.color)
|
|
85898
|
-
: colorNumberToHex(DEFAULT_COLOR_SCALE_MIDPOINT_COLOR);
|
|
85899
|
-
}
|
|
85900
|
-
onMidpointChange(ev) {
|
|
85901
|
-
const type = ev.target.value;
|
|
85792
|
+
onMidpointChange(type) {
|
|
85902
85793
|
const rule = this.state.rules.colorScale;
|
|
85903
85794
|
if (type === "none") {
|
|
85904
85795
|
rule.midpoint = undefined;
|
|
@@ -85921,23 +85812,20 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
85921
85812
|
this.state.rules.colorScale[threshold].value = value;
|
|
85922
85813
|
this.updateConditionalFormat({ rule: this.state.rules.colorScale });
|
|
85923
85814
|
}
|
|
85815
|
+
setColorScaleColor(target, color) {
|
|
85816
|
+
if (!isColorValid(color)) {
|
|
85817
|
+
return;
|
|
85818
|
+
}
|
|
85819
|
+
const point = this.state.rules.colorScale[target];
|
|
85820
|
+
if (point) {
|
|
85821
|
+
point.color = colorToNumber(color);
|
|
85822
|
+
}
|
|
85823
|
+
this.updateConditionalFormat({ rule: this.state.rules.colorScale });
|
|
85824
|
+
this.closeMenus();
|
|
85825
|
+
}
|
|
85924
85826
|
/*****************************************************************************
|
|
85925
85827
|
* Icon Set
|
|
85926
85828
|
****************************************************************************/
|
|
85927
|
-
isInflectionPointInvalid(inflectionPoint) {
|
|
85928
|
-
switch (inflectionPoint) {
|
|
85929
|
-
case "lowerInflectionPoint":
|
|
85930
|
-
return (this.state.errors.includes("ValueLowerInflectionNaN" /* CommandResult.ValueLowerInflectionNaN */) ||
|
|
85931
|
-
this.state.errors.includes("ValueLowerInvalidFormula" /* CommandResult.ValueLowerInvalidFormula */) ||
|
|
85932
|
-
this.state.errors.includes("LowerBiggerThanUpper" /* CommandResult.LowerBiggerThanUpper */));
|
|
85933
|
-
case "upperInflectionPoint":
|
|
85934
|
-
return (this.state.errors.includes("ValueUpperInflectionNaN" /* CommandResult.ValueUpperInflectionNaN */) ||
|
|
85935
|
-
this.state.errors.includes("ValueUpperInvalidFormula" /* CommandResult.ValueUpperInvalidFormula */) ||
|
|
85936
|
-
this.state.errors.includes("LowerBiggerThanUpper" /* CommandResult.LowerBiggerThanUpper */));
|
|
85937
|
-
default:
|
|
85938
|
-
return true;
|
|
85939
|
-
}
|
|
85940
|
-
}
|
|
85941
85829
|
reverseIcons() {
|
|
85942
85830
|
const icons = this.state.rules.iconSet.icons;
|
|
85943
85831
|
const upper = icons.upper;
|
|
@@ -85964,12 +85852,176 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
85964
85852
|
this.state.rules.iconSet[inflectionPoint].value = value;
|
|
85965
85853
|
this.updateConditionalFormat({ rule: this.state.rules.iconSet });
|
|
85966
85854
|
}
|
|
85967
|
-
setInflectionType(inflectionPoint, type
|
|
85855
|
+
setInflectionType(inflectionPoint, type) {
|
|
85968
85856
|
this.state.rules.iconSet[inflectionPoint].type = type;
|
|
85969
85857
|
this.updateConditionalFormat({ rule: this.state.rules.iconSet, suppressErrors: true });
|
|
85970
85858
|
}
|
|
85859
|
+
/*****************************************************************************
|
|
85860
|
+
* DataBar
|
|
85861
|
+
****************************************************************************/
|
|
85862
|
+
get rangeValues() {
|
|
85863
|
+
return [this.state.rules.dataBar.rangeValues || ""];
|
|
85864
|
+
}
|
|
85865
|
+
updateDataBarColor(color) {
|
|
85866
|
+
if (!isColorValid(color)) {
|
|
85867
|
+
return;
|
|
85868
|
+
}
|
|
85869
|
+
this.state.rules.dataBar.color = Number.parseInt(color.slice(1), 16);
|
|
85870
|
+
this.updateConditionalFormat({ rule: this.state.rules.dataBar });
|
|
85871
|
+
}
|
|
85872
|
+
onDataBarRangeUpdate(ranges) {
|
|
85873
|
+
this.state.rules.dataBar.rangeValues = ranges[0];
|
|
85874
|
+
}
|
|
85875
|
+
onDataBarRangeChange() {
|
|
85876
|
+
this.updateConditionalFormat({ rule: this.state.rules.dataBar });
|
|
85877
|
+
}
|
|
85878
|
+
/*****************************************************************************
|
|
85879
|
+
* Common
|
|
85880
|
+
****************************************************************************/
|
|
85881
|
+
toggleMenu(menu) {
|
|
85882
|
+
const isSelected = this.state.openedMenu === menu;
|
|
85883
|
+
this.closeMenus();
|
|
85884
|
+
if (!isSelected) {
|
|
85885
|
+
this.state.openedMenu = menu;
|
|
85886
|
+
}
|
|
85887
|
+
}
|
|
85888
|
+
closeMenus() {
|
|
85889
|
+
this.state.openedMenu = undefined;
|
|
85890
|
+
}
|
|
85891
|
+
getDefaultRules() {
|
|
85892
|
+
return {
|
|
85893
|
+
cellIs: {
|
|
85894
|
+
type: "CellIsRule",
|
|
85895
|
+
operator: "isNotEmpty",
|
|
85896
|
+
values: [],
|
|
85897
|
+
style: { fillColor: "#b6d7a8" },
|
|
85898
|
+
},
|
|
85899
|
+
colorScale: {
|
|
85900
|
+
type: "ColorScaleRule",
|
|
85901
|
+
minimum: { type: "value", color: hexaToInt("EFF7FF") },
|
|
85902
|
+
midpoint: undefined,
|
|
85903
|
+
maximum: { type: "value", color: 0x6aa84f },
|
|
85904
|
+
},
|
|
85905
|
+
iconSet: {
|
|
85906
|
+
type: "IconSetRule",
|
|
85907
|
+
icons: {
|
|
85908
|
+
upper: "arrowGood",
|
|
85909
|
+
middle: "arrowNeutral",
|
|
85910
|
+
lower: "arrowBad",
|
|
85911
|
+
},
|
|
85912
|
+
upperInflectionPoint: {
|
|
85913
|
+
type: "percentage",
|
|
85914
|
+
value: "66",
|
|
85915
|
+
operator: "gt",
|
|
85916
|
+
},
|
|
85917
|
+
lowerInflectionPoint: {
|
|
85918
|
+
type: "percentage",
|
|
85919
|
+
value: "33",
|
|
85920
|
+
operator: "gt",
|
|
85921
|
+
},
|
|
85922
|
+
},
|
|
85923
|
+
dataBar: {
|
|
85924
|
+
type: "DataBarRule",
|
|
85925
|
+
color: 0xd9ead3,
|
|
85926
|
+
},
|
|
85927
|
+
};
|
|
85928
|
+
}
|
|
85929
|
+
}
|
|
85930
|
+
|
|
85931
|
+
class ConditionalFormattingEditor extends owl.Component {
|
|
85932
|
+
static template = "o-spreadsheet-ConditionalFormattingEditor";
|
|
85933
|
+
static components = {
|
|
85934
|
+
SelectionInput,
|
|
85935
|
+
IconPicker,
|
|
85936
|
+
ColorPickerWidget,
|
|
85937
|
+
Section,
|
|
85938
|
+
RoundColorPicker,
|
|
85939
|
+
StandaloneComposer,
|
|
85940
|
+
BadgeSelection,
|
|
85941
|
+
ValidationMessages,
|
|
85942
|
+
SelectMenu,
|
|
85943
|
+
};
|
|
85944
|
+
static props = { cf: Object, isNewCf: Boolean, onCloseSidePanel: Function };
|
|
85945
|
+
getTextDecoration = getTextDecoration;
|
|
85946
|
+
colorNumberToHex = colorNumberToHex;
|
|
85947
|
+
activeSheetId;
|
|
85948
|
+
store;
|
|
85949
|
+
setup() {
|
|
85950
|
+
this.activeSheetId = this.env.model.getters.getActiveSheetId();
|
|
85951
|
+
this.store = useLocalStore(ConditionalFormattingEditorStore, deepCopy(this.props.cf), this.props.isNewCf);
|
|
85952
|
+
owl.useEffect((sheetId, isCfRemoved) => {
|
|
85953
|
+
if (this.activeSheetId !== sheetId || isCfRemoved) {
|
|
85954
|
+
this.env.replaceSidePanel("ConditionalFormatting", `ConditionalFormattingEditor_${this.props.cf.id}`);
|
|
85955
|
+
}
|
|
85956
|
+
}, () => [this.env.model.getters.getActiveSheetId(), this.isEditedCfRemoved]);
|
|
85957
|
+
owl.useExternalListener(window, "click", () => this.store.closeMenus());
|
|
85958
|
+
}
|
|
85959
|
+
get isEditedCfRemoved() {
|
|
85960
|
+
return !Boolean(this.env.model.getters
|
|
85961
|
+
.getConditionalFormats(this.activeSheetId)
|
|
85962
|
+
.find((cf) => cf.id === this.props.cf.id));
|
|
85963
|
+
}
|
|
85964
|
+
get cfTypesValues() {
|
|
85965
|
+
return [
|
|
85966
|
+
{ value: "CellIsRule", label: _t("Single color") },
|
|
85967
|
+
{ value: "ColorScaleRule", label: _t("Color scale") },
|
|
85968
|
+
{ value: "IconSetRule", label: _t("Icon set") },
|
|
85969
|
+
{ value: "DataBarRule", label: _t("Data bar") },
|
|
85970
|
+
];
|
|
85971
|
+
}
|
|
85972
|
+
onSave() {
|
|
85973
|
+
this.store.updateConditionalFormat({});
|
|
85974
|
+
const isSuccessful = this.store.state.errors.length === 0;
|
|
85975
|
+
if (isSuccessful) {
|
|
85976
|
+
this.env.replaceSidePanel("ConditionalFormatting", `ConditionalFormattingEditor_${this.props.cf.id}`);
|
|
85977
|
+
}
|
|
85978
|
+
}
|
|
85979
|
+
onCancel() {
|
|
85980
|
+
if (this.store.state.hasEditedCf) {
|
|
85981
|
+
if (this.props.isNewCf) {
|
|
85982
|
+
this.env.model.dispatch("REMOVE_CONDITIONAL_FORMAT", {
|
|
85983
|
+
sheetId: this.activeSheetId,
|
|
85984
|
+
id: this.props.cf.id,
|
|
85985
|
+
});
|
|
85986
|
+
}
|
|
85987
|
+
else {
|
|
85988
|
+
this.env.model.dispatch("ADD_CONDITIONAL_FORMAT", {
|
|
85989
|
+
cf: this.props.cf,
|
|
85990
|
+
ranges: this.props.cf.ranges.map((range) => this.env.model.getters.getRangeDataFromXc(this.activeSheetId, range)),
|
|
85991
|
+
sheetId: this.activeSheetId,
|
|
85992
|
+
});
|
|
85993
|
+
}
|
|
85994
|
+
}
|
|
85995
|
+
this.env.replaceSidePanel("ConditionalFormatting", `ConditionalFormattingEditor_${this.props.cf.id}`);
|
|
85996
|
+
}
|
|
85997
|
+
/*****************************************************************************
|
|
85998
|
+
* Color Scale Rule
|
|
85999
|
+
****************************************************************************/
|
|
86000
|
+
getThresholdColor(threshold) {
|
|
86001
|
+
return threshold
|
|
86002
|
+
? colorNumberToHex(threshold.color)
|
|
86003
|
+
: colorNumberToHex(DEFAULT_COLOR_SCALE_MIDPOINT_COLOR);
|
|
86004
|
+
}
|
|
86005
|
+
isValueInvalid(threshold) {
|
|
86006
|
+
const errors = this.store.state.errors;
|
|
86007
|
+
switch (threshold) {
|
|
86008
|
+
case "minimum":
|
|
86009
|
+
return (errors.includes("MinInvalidFormula" /* CommandResult.MinInvalidFormula */) ||
|
|
86010
|
+
errors.includes("MinBiggerThanMid" /* CommandResult.MinBiggerThanMid */) ||
|
|
86011
|
+
errors.includes("MinBiggerThanMax" /* CommandResult.MinBiggerThanMax */) ||
|
|
86012
|
+
errors.includes("MinNaN" /* CommandResult.MinNaN */));
|
|
86013
|
+
case "midpoint":
|
|
86014
|
+
return (errors.includes("MidInvalidFormula" /* CommandResult.MidInvalidFormula */) ||
|
|
86015
|
+
errors.includes("MidNaN" /* CommandResult.MidNaN */) ||
|
|
86016
|
+
errors.includes("MidBiggerThanMax" /* CommandResult.MidBiggerThanMax */));
|
|
86017
|
+
case "maximum":
|
|
86018
|
+
return (errors.includes("MaxInvalidFormula" /* CommandResult.MaxInvalidFormula */) || errors.includes("MaxNaN" /* CommandResult.MaxNaN */));
|
|
86019
|
+
default:
|
|
86020
|
+
return false;
|
|
86021
|
+
}
|
|
86022
|
+
}
|
|
85971
86023
|
getColorScaleComposerProps(thresholdType) {
|
|
85972
|
-
const threshold = this.state.rules.colorScale[thresholdType];
|
|
86024
|
+
const threshold = this.store.state.rules.colorScale[thresholdType];
|
|
85973
86025
|
if (!threshold) {
|
|
85974
86026
|
throw new Error("Threshold not found");
|
|
85975
86027
|
}
|
|
@@ -85977,103 +86029,153 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
85977
86029
|
return {
|
|
85978
86030
|
onConfirm: (str) => {
|
|
85979
86031
|
threshold.value = str;
|
|
85980
|
-
this.updateConditionalFormat({ rule: this.state.rules.colorScale });
|
|
86032
|
+
this.store.updateConditionalFormat({ rule: this.store.state.rules.colorScale });
|
|
85981
86033
|
},
|
|
85982
86034
|
composerContent: threshold.value || "",
|
|
85983
86035
|
placeholder: _t("Formula"),
|
|
85984
86036
|
defaultStatic: true,
|
|
85985
86037
|
invalid: isInvalid,
|
|
85986
86038
|
class: "o-sidePanel-composer",
|
|
85987
|
-
defaultRangeSheetId: this.
|
|
86039
|
+
defaultRangeSheetId: this.activeSheetId,
|
|
85988
86040
|
};
|
|
85989
86041
|
}
|
|
86042
|
+
/*****************************************************************************
|
|
86043
|
+
* Icon Set
|
|
86044
|
+
****************************************************************************/
|
|
86045
|
+
isInflectionPointInvalid(inflectionPoint) {
|
|
86046
|
+
const errors = this.store.state.errors;
|
|
86047
|
+
switch (inflectionPoint) {
|
|
86048
|
+
case "lowerInflectionPoint":
|
|
86049
|
+
return (errors.includes("ValueLowerInflectionNaN" /* CommandResult.ValueLowerInflectionNaN */) ||
|
|
86050
|
+
errors.includes("ValueLowerInvalidFormula" /* CommandResult.ValueLowerInvalidFormula */) ||
|
|
86051
|
+
errors.includes("LowerBiggerThanUpper" /* CommandResult.LowerBiggerThanUpper */));
|
|
86052
|
+
case "upperInflectionPoint":
|
|
86053
|
+
return (errors.includes("ValueUpperInflectionNaN" /* CommandResult.ValueUpperInflectionNaN */) ||
|
|
86054
|
+
errors.includes("ValueUpperInvalidFormula" /* CommandResult.ValueUpperInvalidFormula */) ||
|
|
86055
|
+
errors.includes("LowerBiggerThanUpper" /* CommandResult.LowerBiggerThanUpper */));
|
|
86056
|
+
default:
|
|
86057
|
+
return true;
|
|
86058
|
+
}
|
|
86059
|
+
}
|
|
85990
86060
|
getColorIconSetComposerProps(inflectionPoint) {
|
|
85991
|
-
const inflection = this.state.rules.iconSet[inflectionPoint];
|
|
86061
|
+
const inflection = this.store.state.rules.iconSet[inflectionPoint];
|
|
85992
86062
|
const isInvalid = this.isInflectionPointInvalid(inflectionPoint);
|
|
85993
86063
|
return {
|
|
85994
86064
|
onConfirm: (str) => {
|
|
85995
86065
|
inflection.value = str;
|
|
85996
|
-
this.updateConditionalFormat({ rule: this.state.rules.iconSet });
|
|
86066
|
+
this.store.updateConditionalFormat({ rule: this.store.state.rules.iconSet });
|
|
85997
86067
|
},
|
|
85998
86068
|
composerContent: inflection.value || "",
|
|
85999
86069
|
placeholder: _t("Formula"),
|
|
86000
86070
|
defaultStatic: true,
|
|
86001
86071
|
invalid: isInvalid,
|
|
86002
86072
|
class: "o-sidePanel-composer",
|
|
86003
|
-
defaultRangeSheetId: this.
|
|
86073
|
+
defaultRangeSheetId: this.activeSheetId,
|
|
86004
86074
|
};
|
|
86005
86075
|
}
|
|
86006
|
-
|
|
86007
|
-
|
|
86008
|
-
|
|
86009
|
-
|
|
86010
|
-
|
|
86076
|
+
}
|
|
86077
|
+
|
|
86078
|
+
function useHighlightsOnHover(ref, highlightProvider) {
|
|
86079
|
+
const hoverState = useHoveredElement(ref);
|
|
86080
|
+
useHighlights({
|
|
86081
|
+
get highlights() {
|
|
86082
|
+
return hoverState.hovered ? highlightProvider.highlights : [];
|
|
86083
|
+
},
|
|
86084
|
+
});
|
|
86085
|
+
}
|
|
86086
|
+
function useHighlights(highlightProvider) {
|
|
86087
|
+
const stores = useStoreProvider();
|
|
86088
|
+
const store = useLocalStore(HighlightStore);
|
|
86089
|
+
owl.onMounted(() => {
|
|
86090
|
+
store.register(highlightProvider);
|
|
86091
|
+
});
|
|
86092
|
+
let currentHighlights = highlightProvider.highlights;
|
|
86093
|
+
owl.useEffect((highlights) => {
|
|
86094
|
+
if (!deepEquals(highlights, currentHighlights)) {
|
|
86095
|
+
currentHighlights = highlights;
|
|
86096
|
+
stores.trigger("store-updated");
|
|
86097
|
+
}
|
|
86098
|
+
}, () => [highlightProvider.highlights]);
|
|
86099
|
+
}
|
|
86100
|
+
|
|
86101
|
+
class ConditionalFormatPreview extends owl.Component {
|
|
86102
|
+
static template = "o-spreadsheet-ConditionalFormatPreview";
|
|
86103
|
+
static props = {
|
|
86104
|
+
conditionalFormat: Object,
|
|
86105
|
+
onMouseDown: Function,
|
|
86106
|
+
class: String,
|
|
86107
|
+
};
|
|
86108
|
+
icons = ICONS;
|
|
86109
|
+
ref = owl.useRef("cfPreview");
|
|
86110
|
+
setup() {
|
|
86111
|
+
useHighlightsOnHover(this.ref, this);
|
|
86011
86112
|
}
|
|
86012
|
-
|
|
86013
|
-
|
|
86014
|
-
|
|
86113
|
+
get previewImageStyle() {
|
|
86114
|
+
const rule = this.props.conditionalFormat.rule;
|
|
86115
|
+
if (rule.type === "CellIsRule") {
|
|
86116
|
+
return cssPropertiesToCss(cellStyleToCss(rule.style));
|
|
86015
86117
|
}
|
|
86016
|
-
|
|
86017
|
-
|
|
86118
|
+
else if (rule.type === "ColorScaleRule") {
|
|
86119
|
+
const minColor = colorNumberToHex(rule.minimum.color);
|
|
86120
|
+
const midColor = rule.midpoint ? colorNumberToHex(rule.midpoint.color) : null;
|
|
86121
|
+
const maxColor = colorNumberToHex(rule.maximum.color);
|
|
86122
|
+
const baseString = "background-image: linear-gradient(to right, ";
|
|
86123
|
+
return midColor
|
|
86124
|
+
? baseString + minColor + ", " + midColor + ", " + maxColor + ")"
|
|
86125
|
+
: baseString + minColor + ", " + maxColor + ")";
|
|
86126
|
+
}
|
|
86127
|
+
else if (rule.type === "DataBarRule") {
|
|
86128
|
+
const barColor = colorNumberToHex(rule.color);
|
|
86129
|
+
const gradient = `background-image: linear-gradient(to right, ${barColor} 50%, white 50%)`;
|
|
86130
|
+
return `${gradient}; color: ${TEXT_BODY};`;
|
|
86131
|
+
}
|
|
86132
|
+
return "";
|
|
86018
86133
|
}
|
|
86019
|
-
|
|
86020
|
-
this.
|
|
86134
|
+
get description() {
|
|
86135
|
+
const cf = this.props.conditionalFormat;
|
|
86136
|
+
switch (cf.rule.type) {
|
|
86137
|
+
case "CellIsRule":
|
|
86138
|
+
return criterionEvaluatorRegistry
|
|
86139
|
+
.get(cf.rule.operator)
|
|
86140
|
+
.getPreview({ ...cf.rule, type: cf.rule.operator }, this.env.model.getters);
|
|
86141
|
+
case "ColorScaleRule":
|
|
86142
|
+
return CfTerms.ColorScale;
|
|
86143
|
+
case "IconSetRule":
|
|
86144
|
+
return CfTerms.IconSet;
|
|
86145
|
+
case "DataBarRule":
|
|
86146
|
+
return CfTerms.DataBar;
|
|
86147
|
+
}
|
|
86021
86148
|
}
|
|
86022
|
-
|
|
86023
|
-
|
|
86149
|
+
get highlights() {
|
|
86150
|
+
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
86151
|
+
return this.props.conditionalFormat.ranges.map((range) => ({
|
|
86152
|
+
range: this.env.model.getters.getRangeFromSheetXC(sheetId, range),
|
|
86153
|
+
color: HIGHLIGHT_COLOR,
|
|
86154
|
+
fillAlpha: 0.06,
|
|
86155
|
+
}));
|
|
86156
|
+
}
|
|
86157
|
+
editConditionalFormat() {
|
|
86158
|
+
this.env.replaceSidePanel("ConditionalFormattingEditor", "ConditionalFormatting", {
|
|
86159
|
+
cf: this.props.conditionalFormat,
|
|
86160
|
+
isNewCf: false,
|
|
86161
|
+
});
|
|
86162
|
+
}
|
|
86163
|
+
deleteConditionalFormat() {
|
|
86164
|
+
this.env.model.dispatch("REMOVE_CONDITIONAL_FORMAT", {
|
|
86165
|
+
id: this.props.conditionalFormat.id,
|
|
86166
|
+
sheetId: this.env.model.getters.getActiveSheetId(),
|
|
86167
|
+
});
|
|
86024
86168
|
}
|
|
86025
86169
|
}
|
|
86026
86170
|
|
|
86027
|
-
class
|
|
86028
|
-
static template = "o-spreadsheet-
|
|
86171
|
+
class ConditionalFormatPreviewList extends owl.Component {
|
|
86172
|
+
static template = "o-spreadsheet-ConditionalFormatPreviewList";
|
|
86029
86173
|
static props = {
|
|
86030
|
-
selection: { type: Object, optional: true },
|
|
86031
86174
|
onCloseSidePanel: Function,
|
|
86032
86175
|
};
|
|
86033
|
-
static components = {
|
|
86034
|
-
|
|
86035
|
-
|
|
86036
|
-
Section,
|
|
86037
|
-
};
|
|
86038
|
-
activeSheetId;
|
|
86039
|
-
originalEditedCf = undefined;
|
|
86040
|
-
state = owl.useState({
|
|
86041
|
-
mode: "list",
|
|
86042
|
-
});
|
|
86043
|
-
setup() {
|
|
86044
|
-
this.activeSheetId = this.env.model.getters.getActiveSheetId();
|
|
86045
|
-
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
86046
|
-
const rules = this.env.model.getters.getRulesSelection(sheetId, this.props.selection || []);
|
|
86047
|
-
if (rules.length === 1) {
|
|
86048
|
-
const cf = this.conditionalFormats.find((c) => c.id === rules[0]);
|
|
86049
|
-
if (cf) {
|
|
86050
|
-
this.editConditionalFormat(cf);
|
|
86051
|
-
}
|
|
86052
|
-
}
|
|
86053
|
-
owl.onWillUpdateProps((nextProps) => {
|
|
86054
|
-
const newActiveSheetId = this.env.model.getters.getActiveSheetId();
|
|
86055
|
-
if (newActiveSheetId !== this.activeSheetId) {
|
|
86056
|
-
this.activeSheetId = newActiveSheetId;
|
|
86057
|
-
this.switchToList();
|
|
86058
|
-
}
|
|
86059
|
-
else if (nextProps.selection !== this.props.selection) {
|
|
86060
|
-
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
86061
|
-
const rules = this.env.model.getters.getRulesSelection(sheetId, nextProps.selection || []);
|
|
86062
|
-
if (rules.length === 1) {
|
|
86063
|
-
const cf = this.conditionalFormats.find((c) => c.id === rules[0]);
|
|
86064
|
-
if (cf) {
|
|
86065
|
-
this.editConditionalFormat(cf);
|
|
86066
|
-
}
|
|
86067
|
-
}
|
|
86068
|
-
else {
|
|
86069
|
-
this.switchToList();
|
|
86070
|
-
}
|
|
86071
|
-
}
|
|
86072
|
-
else if (!this.editedCF) {
|
|
86073
|
-
this.switchToList();
|
|
86074
|
-
}
|
|
86075
|
-
});
|
|
86076
|
-
}
|
|
86176
|
+
static components = { ConditionalFormatPreview };
|
|
86177
|
+
dragAndDrop = useDragAndDropListItems();
|
|
86178
|
+
cfListRef = owl.useRef("cfList");
|
|
86077
86179
|
get conditionalFormats() {
|
|
86078
86180
|
const cfs = this.env.model.getters.getConditionalFormats(this.env.model.getters.getActiveSheetId());
|
|
86079
86181
|
return cfs.map((cf) => ({
|
|
@@ -86081,66 +86183,129 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
86081
86183
|
rule: localizeCFRule(cf.rule, this.env.model.getters.getLocale()),
|
|
86082
86184
|
}));
|
|
86083
86185
|
}
|
|
86084
|
-
|
|
86085
|
-
this.
|
|
86086
|
-
this.state.editedCfId = undefined;
|
|
86087
|
-
this.originalEditedCf = undefined;
|
|
86186
|
+
getPreviewDivStyle(cf) {
|
|
86187
|
+
return this.dragAndDrop.itemsStyle[cf.id] || "";
|
|
86088
86188
|
}
|
|
86089
|
-
|
|
86090
|
-
|
|
86189
|
+
onPreviewMouseDown(cf, event) {
|
|
86190
|
+
if (event.button !== 0)
|
|
86191
|
+
return;
|
|
86192
|
+
const previewRects = Array.from(this.cfListRef.el.children).map((previewEl) => getBoundingRectAsPOJO(previewEl));
|
|
86193
|
+
const items = this.conditionalFormats.map((cf, index) => ({
|
|
86194
|
+
id: cf.id,
|
|
86195
|
+
size: previewRects[index].height,
|
|
86196
|
+
position: previewRects[index].y,
|
|
86197
|
+
}));
|
|
86198
|
+
this.dragAndDrop.start("vertical", {
|
|
86199
|
+
draggedItemId: cf.id,
|
|
86200
|
+
initialMousePosition: event.clientY,
|
|
86201
|
+
items: items,
|
|
86202
|
+
scrollableContainerEl: this.cfListRef.el,
|
|
86203
|
+
onDragEnd: (cfId, finalIndex) => this.onDragEnd(cfId, finalIndex),
|
|
86204
|
+
});
|
|
86205
|
+
}
|
|
86206
|
+
onAddConditionalFormat() {
|
|
86207
|
+
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
86208
|
+
const zones = this.env.model.getters.getSelectedZones();
|
|
86209
|
+
const cf = {
|
|
86210
|
+
id: this.env.model.uuidGenerator.smallUuid(),
|
|
86211
|
+
rule: {
|
|
86212
|
+
type: "CellIsRule",
|
|
86213
|
+
operator: "isNotEmpty",
|
|
86214
|
+
style: { fillColor: "#b6d7a8" },
|
|
86215
|
+
values: [],
|
|
86216
|
+
},
|
|
86217
|
+
};
|
|
86091
86218
|
this.env.model.dispatch("ADD_CONDITIONAL_FORMAT", {
|
|
86092
|
-
|
|
86093
|
-
ranges: this.env.model.getters
|
|
86094
|
-
|
|
86095
|
-
|
|
86219
|
+
cf,
|
|
86220
|
+
ranges: zones.map((zone) => this.env.model.getters.getRangeDataFromZone(sheetId, zone)),
|
|
86221
|
+
sheetId,
|
|
86222
|
+
});
|
|
86223
|
+
return this.env.replaceSidePanel("ConditionalFormattingEditor", "ConditionalFormatting", {
|
|
86096
86224
|
cf: {
|
|
86097
|
-
|
|
86098
|
-
|
|
86099
|
-
type: "CellIsRule",
|
|
86100
|
-
operator: "isNotEmpty",
|
|
86101
|
-
style: { fillColor: "#b6d7a8" },
|
|
86102
|
-
values: [],
|
|
86103
|
-
},
|
|
86225
|
+
...cf,
|
|
86226
|
+
ranges: zones.map((zone) => zoneToXc(this.env.model.getters.getUnboundedZone(sheetId, zone))),
|
|
86104
86227
|
},
|
|
86228
|
+
isNewCf: true,
|
|
86105
86229
|
});
|
|
86106
|
-
this.state.editedCfId = cfId;
|
|
86107
|
-
this.state.mode = "edit";
|
|
86108
|
-
this.originalEditedCf = undefined;
|
|
86109
|
-
}
|
|
86110
|
-
editConditionalFormat(cf) {
|
|
86111
|
-
this.state.mode = "edit";
|
|
86112
|
-
this.state.editedCfId = cf.id;
|
|
86113
|
-
this.originalEditedCf = cf;
|
|
86114
86230
|
}
|
|
86115
|
-
|
|
86116
|
-
|
|
86117
|
-
|
|
86118
|
-
|
|
86119
|
-
|
|
86120
|
-
|
|
86121
|
-
|
|
86122
|
-
|
|
86123
|
-
else if (this.state.editedCfId) {
|
|
86124
|
-
this.env.model.dispatch("REMOVE_CONDITIONAL_FORMAT", {
|
|
86125
|
-
sheetId: this.activeSheetId,
|
|
86126
|
-
id: this.state.editedCfId,
|
|
86231
|
+
onDragEnd(cfId, finalIndex) {
|
|
86232
|
+
const originalIndex = this.conditionalFormats.findIndex((sheet) => sheet.id === cfId);
|
|
86233
|
+
const delta = originalIndex - finalIndex;
|
|
86234
|
+
if (delta !== 0) {
|
|
86235
|
+
this.env.model.dispatch("CHANGE_CONDITIONAL_FORMAT_PRIORITY", {
|
|
86236
|
+
cfId,
|
|
86237
|
+
delta,
|
|
86238
|
+
sheetId: this.env.model.getters.getActiveSheetId(),
|
|
86127
86239
|
});
|
|
86128
86240
|
}
|
|
86129
|
-
this.switchToList();
|
|
86130
86241
|
}
|
|
86131
|
-
|
|
86132
|
-
|
|
86242
|
+
}
|
|
86243
|
+
|
|
86244
|
+
class DataValidationPreview extends owl.Component {
|
|
86245
|
+
static template = "o-spreadsheet-DataValidationPreview";
|
|
86246
|
+
static props = {
|
|
86247
|
+
rule: Object,
|
|
86248
|
+
};
|
|
86249
|
+
ref = owl.useRef("dvPreview");
|
|
86250
|
+
setup() {
|
|
86251
|
+
useHighlightsOnHover(this.ref, this);
|
|
86252
|
+
}
|
|
86253
|
+
onPreviewClick() {
|
|
86254
|
+
this.env.replaceSidePanel("DataValidationEditor", "DataValidation", {
|
|
86255
|
+
ruleId: this.props.rule.id,
|
|
86256
|
+
});
|
|
86257
|
+
}
|
|
86258
|
+
deleteDataValidation() {
|
|
86259
|
+
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
86260
|
+
this.env.model.dispatch("REMOVE_DATA_VALIDATION_RULE", { sheetId, id: this.props.rule.id });
|
|
86261
|
+
}
|
|
86262
|
+
get highlights() {
|
|
86263
|
+
return this.props.rule.ranges.map((range) => ({
|
|
86264
|
+
range,
|
|
86265
|
+
color: HIGHLIGHT_COLOR,
|
|
86266
|
+
fillAlpha: 0.06,
|
|
86267
|
+
}));
|
|
86268
|
+
}
|
|
86269
|
+
get rangesString() {
|
|
86270
|
+
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
86271
|
+
return this.props.rule.ranges
|
|
86272
|
+
.map((range) => this.env.model.getters.getRangeString(range, sheetId))
|
|
86273
|
+
.join(", ");
|
|
86274
|
+
}
|
|
86275
|
+
get descriptionString() {
|
|
86276
|
+
return criterionEvaluatorRegistry
|
|
86277
|
+
.get(this.props.rule.criterion.type)
|
|
86278
|
+
.getPreview(this.props.rule.criterion, this.env.model.getters);
|
|
86279
|
+
}
|
|
86280
|
+
}
|
|
86281
|
+
|
|
86282
|
+
class DataValidationPanel extends owl.Component {
|
|
86283
|
+
static template = "o-spreadsheet-DataValidationPanel";
|
|
86284
|
+
static props = {
|
|
86285
|
+
onCloseSidePanel: Function,
|
|
86286
|
+
};
|
|
86287
|
+
static components = { DataValidationPreview };
|
|
86288
|
+
addDataValidationRule() {
|
|
86289
|
+
this.env.replaceSidePanel("DataValidationEditor", "DataValidation", {
|
|
86290
|
+
ruleId: this.env.model.uuidGenerator.smallUuid(),
|
|
86291
|
+
});
|
|
86292
|
+
}
|
|
86293
|
+
localizeDVRule(rule) {
|
|
86294
|
+
if (!rule)
|
|
86295
|
+
return rule;
|
|
86296
|
+
const locale = this.env.model.getters.getLocale();
|
|
86297
|
+
return localizeDataValidationRule(rule, locale);
|
|
86298
|
+
}
|
|
86299
|
+
get validationRules() {
|
|
86300
|
+
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
86301
|
+
return this.env.model.getters.getDataValidationRules(sheetId);
|
|
86133
86302
|
}
|
|
86134
86303
|
}
|
|
86135
86304
|
|
|
86136
86305
|
class DataValidationEditor extends owl.Component {
|
|
86137
86306
|
static template = "o-spreadsheet-DataValidationEditor";
|
|
86138
86307
|
static components = { SelectionInput, SelectMenu, Section, ValidationMessages };
|
|
86139
|
-
static props = {
|
|
86140
|
-
rule: { type: Object, optional: true },
|
|
86141
|
-
onExit: Function,
|
|
86142
|
-
onCloseSidePanel: { type: Function, optional: true },
|
|
86143
|
-
};
|
|
86308
|
+
static props = { ruleId: String, onCloseSidePanel: Function };
|
|
86144
86309
|
state = owl.useState({
|
|
86145
86310
|
rule: this.defaultDataValidationRule,
|
|
86146
86311
|
errors: [],
|
|
@@ -86149,12 +86314,13 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
86149
86314
|
editingSheetId;
|
|
86150
86315
|
setup() {
|
|
86151
86316
|
this.editingSheetId = this.env.model.getters.getActiveSheetId();
|
|
86152
|
-
|
|
86317
|
+
const rule = this.env.model.getters.getDataValidationRule(this.editingSheetId, this.props.ruleId);
|
|
86318
|
+
if (rule) {
|
|
86319
|
+
const locale = this.env.model.getters.getLocale();
|
|
86153
86320
|
this.state.rule = {
|
|
86154
|
-
...
|
|
86155
|
-
ranges:
|
|
86321
|
+
...localizeDataValidationRule(rule, locale),
|
|
86322
|
+
ranges: rule.ranges.map((range) => this.env.model.getters.getRangeString(range, this.editingSheetId)),
|
|
86156
86323
|
};
|
|
86157
|
-
this.state.rule.criterion.type = this.props.rule.criterion.type;
|
|
86158
86324
|
}
|
|
86159
86325
|
}
|
|
86160
86326
|
onCriterionTypeChanged(type) {
|
|
@@ -86171,16 +86337,16 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
86171
86337
|
const isBlocking = ev.target.value;
|
|
86172
86338
|
this.state.rule.isBlocking = isBlocking === "true";
|
|
86173
86339
|
}
|
|
86340
|
+
onCancel() {
|
|
86341
|
+
this.env.replaceSidePanel("DataValidation", `DataValidationEditor_${this.props.ruleId}`);
|
|
86342
|
+
}
|
|
86174
86343
|
onSave() {
|
|
86175
|
-
|
|
86176
|
-
|
|
86177
|
-
|
|
86178
|
-
|
|
86179
|
-
}
|
|
86180
|
-
else {
|
|
86181
|
-
this.props.onExit();
|
|
86182
|
-
}
|
|
86344
|
+
const result = this.env.model.dispatch("ADD_DATA_VALIDATION_RULE", this.dispatchPayload);
|
|
86345
|
+
if (!result.isSuccessful) {
|
|
86346
|
+
this.state.errors = result.reasons;
|
|
86347
|
+
return;
|
|
86183
86348
|
}
|
|
86349
|
+
this.env.replaceSidePanel("DataValidation", `DataValidationEditor_${this.props.ruleId}`);
|
|
86184
86350
|
}
|
|
86185
86351
|
get dispatchPayload() {
|
|
86186
86352
|
const rule = { ...this.state.rule, ranges: undefined };
|
|
@@ -86212,7 +86378,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
86212
86378
|
.getSelectedZones()
|
|
86213
86379
|
.map((zone) => zoneToXc(this.env.model.getters.getUnboundedZone(sheetId, zone)));
|
|
86214
86380
|
return {
|
|
86215
|
-
id: this.
|
|
86381
|
+
id: this.props.ruleId,
|
|
86216
86382
|
criterion: { type: "containsText", values: [""] },
|
|
86217
86383
|
ranges,
|
|
86218
86384
|
};
|
|
@@ -86225,75 +86391,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
86225
86391
|
}
|
|
86226
86392
|
}
|
|
86227
86393
|
|
|
86228
|
-
class DataValidationPreview extends owl.Component {
|
|
86229
|
-
static template = "o-spreadsheet-DataValidationPreview";
|
|
86230
|
-
static props = {
|
|
86231
|
-
onClick: Function,
|
|
86232
|
-
rule: Object,
|
|
86233
|
-
};
|
|
86234
|
-
ref = owl.useRef("dvPreview");
|
|
86235
|
-
setup() {
|
|
86236
|
-
useHighlightsOnHover(this.ref, this);
|
|
86237
|
-
}
|
|
86238
|
-
deleteDataValidation() {
|
|
86239
|
-
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
86240
|
-
this.env.model.dispatch("REMOVE_DATA_VALIDATION_RULE", { sheetId, id: this.props.rule.id });
|
|
86241
|
-
}
|
|
86242
|
-
get highlights() {
|
|
86243
|
-
return this.props.rule.ranges.map((range) => ({
|
|
86244
|
-
range,
|
|
86245
|
-
color: HIGHLIGHT_COLOR,
|
|
86246
|
-
fillAlpha: 0.06,
|
|
86247
|
-
}));
|
|
86248
|
-
}
|
|
86249
|
-
get rangesString() {
|
|
86250
|
-
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
86251
|
-
return this.props.rule.ranges
|
|
86252
|
-
.map((range) => this.env.model.getters.getRangeString(range, sheetId))
|
|
86253
|
-
.join(", ");
|
|
86254
|
-
}
|
|
86255
|
-
get descriptionString() {
|
|
86256
|
-
return criterionEvaluatorRegistry
|
|
86257
|
-
.get(this.props.rule.criterion.type)
|
|
86258
|
-
.getPreview(this.props.rule.criterion, this.env.model.getters);
|
|
86259
|
-
}
|
|
86260
|
-
}
|
|
86261
|
-
|
|
86262
|
-
class DataValidationPanel extends owl.Component {
|
|
86263
|
-
static template = "o-spreadsheet-DataValidationPanel";
|
|
86264
|
-
static props = {
|
|
86265
|
-
onCloseSidePanel: Function,
|
|
86266
|
-
};
|
|
86267
|
-
static components = { DataValidationPreview, DataValidationEditor };
|
|
86268
|
-
state = owl.useState({ mode: "list", activeRule: undefined });
|
|
86269
|
-
onPreviewClick(id) {
|
|
86270
|
-
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
86271
|
-
const rule = this.env.model.getters.getDataValidationRule(sheetId, id);
|
|
86272
|
-
if (rule) {
|
|
86273
|
-
this.state.mode = "edit";
|
|
86274
|
-
this.state.activeRule = rule;
|
|
86275
|
-
}
|
|
86276
|
-
}
|
|
86277
|
-
addDataValidationRule() {
|
|
86278
|
-
this.state.mode = "edit";
|
|
86279
|
-
this.state.activeRule = undefined;
|
|
86280
|
-
}
|
|
86281
|
-
onExitEditMode() {
|
|
86282
|
-
this.state.mode = "list";
|
|
86283
|
-
this.state.activeRule = undefined;
|
|
86284
|
-
}
|
|
86285
|
-
localizeDVRule(rule) {
|
|
86286
|
-
if (!rule)
|
|
86287
|
-
return rule;
|
|
86288
|
-
const locale = this.env.model.getters.getLocale();
|
|
86289
|
-
return localizeDataValidationRule(rule, locale);
|
|
86290
|
-
}
|
|
86291
|
-
get validationRules() {
|
|
86292
|
-
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
86293
|
-
return this.env.model.getters.getDataValidationRules(sheetId);
|
|
86294
|
-
}
|
|
86295
|
-
}
|
|
86296
|
-
|
|
86297
86394
|
const FIND_AND_REPLACE_HIGHLIGHT_COLOR = "#8B008B";
|
|
86298
86395
|
var Direction;
|
|
86299
86396
|
(function (Direction) {
|
|
@@ -89171,7 +89268,18 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
89171
89268
|
const sidePanelRegistry = new Registry$1();
|
|
89172
89269
|
sidePanelRegistry.add("ConditionalFormatting", {
|
|
89173
89270
|
title: _t("Conditional formatting"),
|
|
89174
|
-
Body:
|
|
89271
|
+
Body: ConditionalFormatPreviewList,
|
|
89272
|
+
});
|
|
89273
|
+
sidePanelRegistry.add("ConditionalFormattingEditor", {
|
|
89274
|
+
title: _t("Conditional formatting"),
|
|
89275
|
+
Body: ConditionalFormattingEditor,
|
|
89276
|
+
computeState: (getters, props) => {
|
|
89277
|
+
return {
|
|
89278
|
+
isOpen: true,
|
|
89279
|
+
props,
|
|
89280
|
+
key: `ConditionalFormattingEditor_${props.cf.id}`,
|
|
89281
|
+
};
|
|
89282
|
+
},
|
|
89175
89283
|
});
|
|
89176
89284
|
sidePanelRegistry.add("ChartPanel", {
|
|
89177
89285
|
title: _t("Chart"),
|
|
@@ -89208,6 +89316,13 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
89208
89316
|
sidePanelRegistry.add("DataValidationEditor", {
|
|
89209
89317
|
title: _t("Data validation"),
|
|
89210
89318
|
Body: DataValidationEditor,
|
|
89319
|
+
computeState: (getters, props) => {
|
|
89320
|
+
return {
|
|
89321
|
+
isOpen: true,
|
|
89322
|
+
props,
|
|
89323
|
+
key: `DataValidationEditor_${props.ruleId}`,
|
|
89324
|
+
};
|
|
89325
|
+
},
|
|
89211
89326
|
});
|
|
89212
89327
|
sidePanelRegistry.add("MoreFormats", {
|
|
89213
89328
|
title: _t("More formats"),
|
|
@@ -89894,7 +90009,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
89894
90009
|
});
|
|
89895
90010
|
return !(rect.width === 0 || rect.height === 0);
|
|
89896
90011
|
}
|
|
89897
|
-
onGridResized(
|
|
90012
|
+
onGridResized() {
|
|
90013
|
+
const { height, width } = this.props.getGridSize();
|
|
89898
90014
|
this.env.model.dispatch("RESIZE_SHEETVIEW", {
|
|
89899
90015
|
width: width - HEADER_WIDTH,
|
|
89900
90016
|
height: height - HEADER_HEIGHT,
|
|
@@ -93442,10 +93558,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
93442
93558
|
});
|
|
93443
93559
|
}
|
|
93444
93560
|
get gridContainer() {
|
|
93445
|
-
const
|
|
93446
|
-
|
|
93447
|
-
const { end } = this.env.model.getters.getColDimensions(sheetId, right);
|
|
93448
|
-
return cssPropertiesToCss({ "max-width": `${end}px` });
|
|
93561
|
+
const maxWidth = this.getMaxSheetWidth();
|
|
93562
|
+
return cssPropertiesToCss({ "max-width": `${maxWidth}px` });
|
|
93449
93563
|
}
|
|
93450
93564
|
get gridOverlayDimensions() {
|
|
93451
93565
|
return cssPropertiesToCss({
|
|
@@ -93477,10 +93591,12 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
93477
93591
|
onClosePopover() {
|
|
93478
93592
|
this.cellPopovers.close();
|
|
93479
93593
|
}
|
|
93480
|
-
onGridResized(
|
|
93594
|
+
onGridResized() {
|
|
93595
|
+
const { height, width } = this.props.getGridSize();
|
|
93596
|
+
const maxWidth = this.getMaxSheetWidth();
|
|
93481
93597
|
this.env.model.dispatch("RESIZE_SHEETVIEW", {
|
|
93482
|
-
width: width,
|
|
93483
|
-
height
|
|
93598
|
+
width: Math.min(maxWidth, width),
|
|
93599
|
+
height,
|
|
93484
93600
|
gridOffsetX: 0,
|
|
93485
93601
|
gridOffsetY: 0,
|
|
93486
93602
|
});
|
|
@@ -93498,6 +93614,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
93498
93614
|
...this.env.model.getters.getSheetViewDimensionWithHeaders(),
|
|
93499
93615
|
};
|
|
93500
93616
|
}
|
|
93617
|
+
getMaxSheetWidth() {
|
|
93618
|
+
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
93619
|
+
const { right } = this.env.model.getters.getSheetZone(sheetId);
|
|
93620
|
+
return this.env.model.getters.getColDimensions(sheetId, right).end;
|
|
93621
|
+
}
|
|
93501
93622
|
}
|
|
93502
93623
|
|
|
93503
93624
|
class AbstractHeaderGroup extends owl.Component {
|
|
@@ -97953,9 +98074,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
97953
98074
|
exports.tokenize = tokenize;
|
|
97954
98075
|
|
|
97955
98076
|
|
|
97956
|
-
__info__.version = "19.2.0-alpha.
|
|
97957
|
-
__info__.date = "
|
|
97958
|
-
__info__.hash = "
|
|
98077
|
+
__info__.version = "19.2.0-alpha.2";
|
|
98078
|
+
__info__.date = "2026-01-07T16:21:35.251Z";
|
|
98079
|
+
__info__.hash = "ac2fa3e";
|
|
97959
98080
|
|
|
97960
98081
|
|
|
97961
98082
|
})(this.o_spreadsheet = this.o_spreadsheet || {}, owl);
|