@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
|
@@ -143,12 +143,11 @@ type BarChartRuntime = {
|
|
|
143
143
|
interface GenericCriterion {
|
|
144
144
|
type: GenericCriterionType;
|
|
145
145
|
values: string[];
|
|
146
|
+
isPercent?: boolean;
|
|
147
|
+
isBottom?: boolean;
|
|
146
148
|
}
|
|
147
|
-
type GenericCriterionType = "containsText" | "notContainsText" | "isEqualText" | "isEmail" | "isLink" | "dateIs" | "dateIsBefore" | "dateIsOnOrBefore" | "dateIsAfter" | "dateIsOnOrAfter" | "dateIsBetween" | "dateIsNotBetween" | "dateIsValid" | "isEqual" | "isNotEqual" | "isGreaterThan" | "isGreaterOrEqualTo" | "isLessThan" | "isLessOrEqualTo" | "isBetween" | "isNotBetween" | "isBoolean" | "isValueInList" | "isValueInRange" | "customFormula" | "beginsWithText" | "endsWithText" | "isNotEmpty" | "isEmpty";
|
|
149
|
+
type GenericCriterionType = "containsText" | "notContainsText" | "isEqualText" | "isEmail" | "isLink" | "dateIs" | "dateIsBefore" | "dateIsOnOrBefore" | "dateIsAfter" | "dateIsOnOrAfter" | "dateIsBetween" | "dateIsNotBetween" | "dateIsValid" | "isEqual" | "isNotEqual" | "isGreaterThan" | "isGreaterOrEqualTo" | "isLessThan" | "isLessOrEqualTo" | "isBetween" | "isNotBetween" | "isBoolean" | "isValueInList" | "isValueInRange" | "customFormula" | "beginsWithText" | "endsWithText" | "isNotEmpty" | "isEmpty" | "top10";
|
|
148
150
|
type DateCriterionValue = "today" | "tomorrow" | "yesterday" | "lastWeek" | "lastMonth" | "lastYear" | "exactDate";
|
|
149
|
-
type EvaluatedCriterion<T extends GenericCriterion = GenericCriterion> = Omit<T, "values"> & {
|
|
150
|
-
values: CellValue[];
|
|
151
|
-
};
|
|
152
151
|
|
|
153
152
|
interface RangePart {
|
|
154
153
|
readonly colFixed: boolean;
|
|
@@ -646,6 +645,8 @@ interface CellIsRule extends SingleColorRule {
|
|
|
646
645
|
operator: ConditionalFormattingOperatorValues;
|
|
647
646
|
values: string[];
|
|
648
647
|
dateValue?: DateCriterionValue;
|
|
648
|
+
isPercent?: boolean;
|
|
649
|
+
isBottom?: boolean;
|
|
649
650
|
}
|
|
650
651
|
type ThresholdType = "value" | "number" | "percentage" | "percentile" | "formula";
|
|
651
652
|
type ColorScaleThreshold = {
|
|
@@ -688,7 +689,7 @@ interface IconSetRule {
|
|
|
688
689
|
upperInflectionPoint: IconThreshold;
|
|
689
690
|
lowerInflectionPoint: IconThreshold;
|
|
690
691
|
}
|
|
691
|
-
declare const cfOperators: readonly ["containsText", "notContainsText", "isGreaterThan", "isGreaterOrEqualTo", "isLessThan", "isLessOrEqualTo", "isBetween", "isNotBetween", "beginsWithText", "endsWithText", "isNotEmpty", "isEmpty", "isNotEqual", "isEqual", "customFormula", "dateIs", "dateIsBefore", "dateIsAfter", "dateIsOnOrBefore", "dateIsOnOrAfter"];
|
|
692
|
+
declare const cfOperators: readonly ["containsText", "notContainsText", "isGreaterThan", "isGreaterOrEqualTo", "isLessThan", "isLessOrEqualTo", "isBetween", "isNotBetween", "beginsWithText", "endsWithText", "isNotEmpty", "isEmpty", "isNotEqual", "isEqual", "customFormula", "dateIs", "dateIsBefore", "dateIsAfter", "dateIsOnOrBefore", "dateIsOnOrAfter", "top10"];
|
|
692
693
|
type ConditionalFormattingOperatorValues = (typeof cfOperators)[number];
|
|
693
694
|
|
|
694
695
|
interface ConditionalFormatState {
|
|
@@ -2535,6 +2536,7 @@ declare class Session extends EventBus<CollaborativeEvent> {
|
|
|
2535
2536
|
private onClientJoined;
|
|
2536
2537
|
private onClientLeft;
|
|
2537
2538
|
private sendUpdateMessage;
|
|
2539
|
+
private sendToTransport;
|
|
2538
2540
|
/**
|
|
2539
2541
|
* Send the next pending message
|
|
2540
2542
|
*/
|
|
@@ -2755,6 +2757,9 @@ type SheetValidationResult = {
|
|
|
2755
2757
|
declare class EvaluationDataValidationPlugin extends CoreViewPlugin {
|
|
2756
2758
|
static getters: readonly ["getDataValidationInvalidCriterionValueMessage", "getInvalidDataValidationMessage", "getValidationResultForCellValue", "getDataValidationRangeValues", "isCellValidCheckbox", "getDataValidationCellStyle", "getDataValidationChipStyle", "isDataValidationInvalid"];
|
|
2757
2759
|
validationResults: Record<UID, SheetValidationResult>;
|
|
2760
|
+
criterionPreComputeResult: Record<UID, {
|
|
2761
|
+
[dvRuleId: UID]: unknown;
|
|
2762
|
+
}>;
|
|
2758
2763
|
handle(cmd: CoreViewCommand): void;
|
|
2759
2764
|
isDataValidationInvalid(cellPosition: CellPosition): boolean;
|
|
2760
2765
|
getDataValidationCellStyle(position: CellPosition): Style | undefined;
|
|
@@ -2766,7 +2771,7 @@ declare class EvaluationDataValidationPlugin extends CoreViewPlugin {
|
|
|
2766
2771
|
* The value must be canonicalized.
|
|
2767
2772
|
*/
|
|
2768
2773
|
getDataValidationInvalidCriterionValueMessage(criterionType: DataValidationCriterionType, value: string): string | undefined;
|
|
2769
|
-
getDataValidationRangeValues(sheetId: UID, criterion:
|
|
2774
|
+
getDataValidationRangeValues(sheetId: UID, criterion: GenericCriterion): {
|
|
2770
2775
|
value: string;
|
|
2771
2776
|
label: string;
|
|
2772
2777
|
}[];
|
|
@@ -3,8 +3,8 @@
|
|
|
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
5
|
* @version 19.1.0-alpha.3
|
|
6
|
-
* @date
|
|
7
|
-
* @hash
|
|
6
|
+
* @date 2026-01-07T16:20:57.293Z
|
|
7
|
+
* @hash ac2fa3e
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
class FunctionCodeBuilder {
|
|
@@ -14251,6 +14251,7 @@ const DVTerms = {
|
|
|
14251
14251
|
dateValue: _t("The value must be a date"),
|
|
14252
14252
|
validRange: _t("The value must be a valid range"),
|
|
14253
14253
|
validFormula: _t("The formula must be valid"),
|
|
14254
|
+
positiveNumber: _t("The value must be a positive number"),
|
|
14254
14255
|
},
|
|
14255
14256
|
Errors: {
|
|
14256
14257
|
["InvalidRange" /* CommandResult.InvalidRange */]: _t("The range is invalid."),
|
|
@@ -18112,7 +18113,7 @@ class ReadonlyTransportFilter {
|
|
|
18112
18113
|
if (message.type === "CLIENT_JOINED" ||
|
|
18113
18114
|
message.type === "CLIENT_LEFT" ||
|
|
18114
18115
|
message.type === "CLIENT_MOVED") {
|
|
18115
|
-
this.transportService.sendMessage(message);
|
|
18116
|
+
await this.transportService.sendMessage(message);
|
|
18116
18117
|
}
|
|
18117
18118
|
// ignore all other messages
|
|
18118
18119
|
}
|
|
@@ -20731,7 +20732,7 @@ class Session extends EventBus {
|
|
|
20731
20732
|
}
|
|
20732
20733
|
delete this.clients[this.clientId];
|
|
20733
20734
|
this.transportService.leave(this.clientId);
|
|
20734
|
-
this.
|
|
20735
|
+
this.sendToTransport({
|
|
20735
20736
|
type: "CLIENT_LEFT",
|
|
20736
20737
|
clientId: this.clientId,
|
|
20737
20738
|
version: MESSAGE_VERSION,
|
|
@@ -20745,7 +20746,7 @@ class Session extends EventBus {
|
|
|
20745
20746
|
return;
|
|
20746
20747
|
}
|
|
20747
20748
|
const snapshotId = this.uuidGenerator.uuidv4();
|
|
20748
|
-
await this.
|
|
20749
|
+
await this.sendToTransport({
|
|
20749
20750
|
type: "SNAPSHOT",
|
|
20750
20751
|
nextRevisionId: snapshotId,
|
|
20751
20752
|
serverRevisionId: this.serverRevisionId,
|
|
@@ -20793,10 +20794,14 @@ class Session extends EventBus {
|
|
|
20793
20794
|
const type = currentPosition ? "CLIENT_MOVED" : "CLIENT_JOINED";
|
|
20794
20795
|
const client = this.getCurrentClient();
|
|
20795
20796
|
this.clients[this.clientId] = { ...client, position };
|
|
20796
|
-
this.
|
|
20797
|
+
this.sendToTransport({
|
|
20797
20798
|
type,
|
|
20798
20799
|
version: MESSAGE_VERSION,
|
|
20799
20800
|
client: { ...client, position },
|
|
20801
|
+
}).then(() => {
|
|
20802
|
+
if (this.pendingMessages.length > 0 && !this.waitingAck) {
|
|
20803
|
+
this.sendPendingMessage();
|
|
20804
|
+
}
|
|
20800
20805
|
});
|
|
20801
20806
|
}
|
|
20802
20807
|
/**
|
|
@@ -20877,7 +20882,7 @@ class Session extends EventBus {
|
|
|
20877
20882
|
if (client) {
|
|
20878
20883
|
const { position } = client;
|
|
20879
20884
|
if (position) {
|
|
20880
|
-
this.
|
|
20885
|
+
this.sendToTransport({
|
|
20881
20886
|
type: "CLIENT_MOVED",
|
|
20882
20887
|
version: MESSAGE_VERSION,
|
|
20883
20888
|
client: { ...client, position },
|
|
@@ -20898,6 +20903,10 @@ class Session extends EventBus {
|
|
|
20898
20903
|
}
|
|
20899
20904
|
this.sendPendingMessage();
|
|
20900
20905
|
}
|
|
20906
|
+
async sendToTransport(message) {
|
|
20907
|
+
// wrap in an async function to ensure it returns a promise
|
|
20908
|
+
return this.transportService.sendMessage(message);
|
|
20909
|
+
}
|
|
20901
20910
|
/**
|
|
20902
20911
|
* Send the next pending message
|
|
20903
20912
|
*/
|
|
@@ -20926,9 +20935,14 @@ class Session extends EventBus {
|
|
|
20926
20935
|
${JSON.stringify(message)}`);
|
|
20927
20936
|
}
|
|
20928
20937
|
this.waitingAck = true;
|
|
20929
|
-
this.
|
|
20938
|
+
this.sendToTransport({
|
|
20930
20939
|
...message,
|
|
20931
20940
|
serverRevisionId: this.serverRevisionId,
|
|
20941
|
+
}).catch((e) => {
|
|
20942
|
+
if (!(e instanceof ClientDisconnectedError)) {
|
|
20943
|
+
throw e.cause || e;
|
|
20944
|
+
}
|
|
20945
|
+
this.waitingAck = false;
|
|
20932
20946
|
});
|
|
20933
20947
|
}
|
|
20934
20948
|
acknowledge(message) {
|
|
@@ -22389,6 +22403,7 @@ const CF_OPERATOR_TYPE_CONVERSION_MAP = {
|
|
|
22389
22403
|
greaterThanOrEqual: "isGreaterOrEqualTo",
|
|
22390
22404
|
lessThan: "isLessThan",
|
|
22391
22405
|
lessThanOrEqual: "isLessOrEqualTo",
|
|
22406
|
+
top10: "top10",
|
|
22392
22407
|
};
|
|
22393
22408
|
/** Conversion map CF types in XLSX <=> Cf types in o_spreadsheet */
|
|
22394
22409
|
const CF_TYPE_CONVERSION_MAP = {
|
|
@@ -22929,6 +22944,7 @@ function convertConditionalFormats(xlsxCfs, dxfs, warningManager) {
|
|
|
22929
22944
|
const rule = cf.cfRules[0];
|
|
22930
22945
|
let operator;
|
|
22931
22946
|
const values = [];
|
|
22947
|
+
const cfAdditionalProperties = {};
|
|
22932
22948
|
if (rule.dxfId === undefined &&
|
|
22933
22949
|
!(rule.type === "colorScale" || rule.type === "iconSet" || rule.type === "dataBar"))
|
|
22934
22950
|
continue;
|
|
@@ -22937,7 +22953,6 @@ function convertConditionalFormats(xlsxCfs, dxfs, warningManager) {
|
|
|
22937
22953
|
case "containsErrors":
|
|
22938
22954
|
case "notContainsErrors":
|
|
22939
22955
|
case "duplicateValues":
|
|
22940
|
-
case "top10":
|
|
22941
22956
|
case "uniqueValues":
|
|
22942
22957
|
case "timePeriod":
|
|
22943
22958
|
// Not supported
|
|
@@ -22988,6 +23003,18 @@ function convertConditionalFormats(xlsxCfs, dxfs, warningManager) {
|
|
|
22988
23003
|
values.push(prefixFormulaWithEqual(rule.formula[1]));
|
|
22989
23004
|
}
|
|
22990
23005
|
break;
|
|
23006
|
+
case "top10":
|
|
23007
|
+
if (rule.rank === undefined)
|
|
23008
|
+
continue;
|
|
23009
|
+
operator = CF_OPERATOR_TYPE_CONVERSION_MAP[rule.type];
|
|
23010
|
+
values.push(rule.rank.toString());
|
|
23011
|
+
if (rule.percent) {
|
|
23012
|
+
cfAdditionalProperties.isPercent = true;
|
|
23013
|
+
}
|
|
23014
|
+
if (rule.bottom) {
|
|
23015
|
+
cfAdditionalProperties.isBottom = true;
|
|
23016
|
+
}
|
|
23017
|
+
break;
|
|
22991
23018
|
}
|
|
22992
23019
|
if (operator && rule.dxfId !== undefined) {
|
|
22993
23020
|
cfs.push({
|
|
@@ -22998,6 +23025,7 @@ function convertConditionalFormats(xlsxCfs, dxfs, warningManager) {
|
|
|
22998
23025
|
type: "CellIsRule",
|
|
22999
23026
|
operator: operator,
|
|
23000
23027
|
values: values,
|
|
23028
|
+
...cfAdditionalProperties,
|
|
23001
23029
|
style: convertStyle({ fontStyle: dxfs[rule.dxfId].font, fillStyle: dxfs[rule.dxfId].fill }, warningManager),
|
|
23002
23030
|
},
|
|
23003
23031
|
});
|
|
@@ -23291,6 +23319,8 @@ function convertOperator(operator) {
|
|
|
23291
23319
|
return "greaterThanOrEqual";
|
|
23292
23320
|
case "dateIsOnOrBefore":
|
|
23293
23321
|
return "lessThanOrEqual";
|
|
23322
|
+
case "top10":
|
|
23323
|
+
return "top10";
|
|
23294
23324
|
}
|
|
23295
23325
|
}
|
|
23296
23326
|
// -------------------------------------
|
|
@@ -23910,17 +23940,41 @@ function toCriterionDateNumber(dateValue) {
|
|
|
23910
23940
|
const today = DateTime.now();
|
|
23911
23941
|
switch (dateValue) {
|
|
23912
23942
|
case "today":
|
|
23913
|
-
return jsDateToNumber(today);
|
|
23914
|
-
case "yesterday":
|
|
23915
|
-
|
|
23916
|
-
|
|
23917
|
-
|
|
23943
|
+
return Math.floor(jsDateToNumber(today));
|
|
23944
|
+
case "yesterday": {
|
|
23945
|
+
today.setDate(today.getDate() - 1);
|
|
23946
|
+
return Math.floor(jsDateToNumber(today));
|
|
23947
|
+
}
|
|
23948
|
+
case "tomorrow": {
|
|
23949
|
+
today.setDate(today.getDate() + 1);
|
|
23950
|
+
return Math.floor(jsDateToNumber(today));
|
|
23951
|
+
}
|
|
23918
23952
|
case "lastWeek":
|
|
23919
|
-
|
|
23920
|
-
|
|
23921
|
-
|
|
23953
|
+
today.setDate(today.getDate() - 6);
|
|
23954
|
+
return Math.floor(jsDateToNumber(today));
|
|
23955
|
+
case "lastMonth": {
|
|
23956
|
+
const lastMonth = today.getMonth() === 0 ? 11 : today.getMonth() - 1;
|
|
23957
|
+
const dateInLastMonth = new DateTime(today.getFullYear(), lastMonth, 1);
|
|
23958
|
+
if (today.getDate() > getDaysInMonth(dateInLastMonth)) {
|
|
23959
|
+
today.setDate(1);
|
|
23960
|
+
}
|
|
23961
|
+
else {
|
|
23962
|
+
today.setDate(today.getDate() + 1);
|
|
23963
|
+
today.setMonth(today.getMonth() - 1);
|
|
23964
|
+
}
|
|
23965
|
+
return Math.floor(jsDateToNumber(today));
|
|
23966
|
+
}
|
|
23922
23967
|
case "lastYear":
|
|
23923
|
-
|
|
23968
|
+
// Handle leap year case
|
|
23969
|
+
if (today.getMonth() === 1 && today.getDate() === 29) {
|
|
23970
|
+
today.setDate(28);
|
|
23971
|
+
today.setFullYear(today.getFullYear() - 1);
|
|
23972
|
+
}
|
|
23973
|
+
else {
|
|
23974
|
+
today.setDate(today.getDate() + 1);
|
|
23975
|
+
today.setFullYear(today.getFullYear() - 1);
|
|
23976
|
+
}
|
|
23977
|
+
return Math.floor(jsDateToNumber(today));
|
|
23924
23978
|
}
|
|
23925
23979
|
}
|
|
23926
23980
|
/** Get all the dates values of a criterion converted to numbers, converting date values such as "today" to actual dates */
|
|
@@ -28945,7 +28999,7 @@ criterionEvaluatorRegistry.add("dateIs", {
|
|
|
28945
28999
|
return false;
|
|
28946
29000
|
}
|
|
28947
29001
|
if (["lastWeek", "lastMonth", "lastYear"].includes(criterion.dateValue)) {
|
|
28948
|
-
const today =
|
|
29002
|
+
const today = Math.floor(jsDateToNumber(DateTime.now()));
|
|
28949
29003
|
return isDateBetween(dateValue, today, criterionValue);
|
|
28950
29004
|
}
|
|
28951
29005
|
return areDatesSameDay(dateValue, criterionValue);
|
|
@@ -29327,15 +29381,20 @@ criterionEvaluatorRegistry.add("isValueInList", {
|
|
|
29327
29381
|
getPreview: (criterion) => _t("Value one of: %s", criterion.values.join(", ")),
|
|
29328
29382
|
});
|
|
29329
29383
|
criterionEvaluatorRegistry.add("isValueInRange", {
|
|
29330
|
-
type: "
|
|
29331
|
-
|
|
29384
|
+
type: "isValueInRange",
|
|
29385
|
+
preComputeCriterion: (criterion, criterionRanges, getters) => {
|
|
29386
|
+
if (criterionRanges.length === 0) {
|
|
29387
|
+
return new Set();
|
|
29388
|
+
}
|
|
29389
|
+
const sheetId = criterionRanges[0].sheetId;
|
|
29390
|
+
const criterionValues = getters.getDataValidationRangeValues(sheetId, criterion);
|
|
29391
|
+
return new Set(criterionValues.map((value) => value.value.toString().toLowerCase()));
|
|
29392
|
+
},
|
|
29393
|
+
isValueValid: (value, criterion, valuesSet) => {
|
|
29332
29394
|
if (!value) {
|
|
29333
29395
|
return false;
|
|
29334
29396
|
}
|
|
29335
|
-
|
|
29336
|
-
return criterionValues
|
|
29337
|
-
.map((value) => value.value.toLowerCase())
|
|
29338
|
-
.includes(value.toString().toLowerCase());
|
|
29397
|
+
return valuesSet.has(value.toString().toLowerCase());
|
|
29339
29398
|
},
|
|
29340
29399
|
getErrorString: (criterion) => _t("The value must be a value in the range %s", String(criterion.values[0])),
|
|
29341
29400
|
isCriterionValueValid: (value) => rangeReference.test(value),
|
|
@@ -29412,6 +29471,67 @@ criterionEvaluatorRegistry.add("isNotEmpty", {
|
|
|
29412
29471
|
name: _t("Is not empty"),
|
|
29413
29472
|
getPreview: () => _t("Is not empty"),
|
|
29414
29473
|
});
|
|
29474
|
+
criterionEvaluatorRegistry.add("top10", {
|
|
29475
|
+
type: "top10",
|
|
29476
|
+
preComputeCriterion: (criterion, criterionRanges, getters) => {
|
|
29477
|
+
let value = tryToNumber(criterion.values[0], DEFAULT_LOCALE);
|
|
29478
|
+
if (value === undefined || value <= 0) {
|
|
29479
|
+
return undefined;
|
|
29480
|
+
}
|
|
29481
|
+
const numberValues = [];
|
|
29482
|
+
for (const range of criterionRanges) {
|
|
29483
|
+
for (const value of getters.getRangeValues(range)) {
|
|
29484
|
+
if (typeof value === "number") {
|
|
29485
|
+
numberValues.push(value);
|
|
29486
|
+
}
|
|
29487
|
+
}
|
|
29488
|
+
}
|
|
29489
|
+
const sortedValues = numberValues.sort((a, b) => a - b);
|
|
29490
|
+
if (criterion.isPercent) {
|
|
29491
|
+
value = clip(value, 1, 100);
|
|
29492
|
+
}
|
|
29493
|
+
let index = 0;
|
|
29494
|
+
if (criterion.isBottom && !criterion.isPercent) {
|
|
29495
|
+
index = value - 1;
|
|
29496
|
+
}
|
|
29497
|
+
else if (criterion.isBottom && criterion.isPercent) {
|
|
29498
|
+
index = Math.floor((sortedValues.length * value) / 100) - 1;
|
|
29499
|
+
}
|
|
29500
|
+
else if (!criterion.isBottom && criterion.isPercent) {
|
|
29501
|
+
index = sortedValues.length - Math.floor((sortedValues.length * value) / 100);
|
|
29502
|
+
}
|
|
29503
|
+
else {
|
|
29504
|
+
index = sortedValues.length - value;
|
|
29505
|
+
}
|
|
29506
|
+
index = clip(index, 0, sortedValues.length - 1);
|
|
29507
|
+
return sortedValues[index];
|
|
29508
|
+
},
|
|
29509
|
+
isValueValid: (value, criterion, threshold) => {
|
|
29510
|
+
if (typeof value !== "number" || threshold === undefined) {
|
|
29511
|
+
return false;
|
|
29512
|
+
}
|
|
29513
|
+
return criterion.isBottom ? value <= threshold : value >= threshold;
|
|
29514
|
+
},
|
|
29515
|
+
getErrorString: (criterion) => {
|
|
29516
|
+
const args = {
|
|
29517
|
+
value: String(criterion.values[0]),
|
|
29518
|
+
percentSymbol: criterion.isPercent ? "%" : "",
|
|
29519
|
+
};
|
|
29520
|
+
return criterion.isBottom
|
|
29521
|
+
? _t("The value must be in bottom %(value)s%(percentSymbol)s", args)
|
|
29522
|
+
: _t("The value must be in top %(value)s%(percentSymbol)s", args);
|
|
29523
|
+
},
|
|
29524
|
+
isCriterionValueValid: (value) => checkValueIsPositiveNumber(value),
|
|
29525
|
+
criterionValueErrorString: DVTerms.CriterionError.positiveNumber,
|
|
29526
|
+
numberOfValues: () => 1,
|
|
29527
|
+
name: _t("Is in Top/Bottom ranking"),
|
|
29528
|
+
getPreview: (criterion) => {
|
|
29529
|
+
const args = { value: criterion.values[0], percentSymbol: criterion.isPercent ? "%" : "" };
|
|
29530
|
+
return criterion.isBottom
|
|
29531
|
+
? _t("Value is in bottom %(value)s%(percentSymbol)s", args)
|
|
29532
|
+
: _t("Value is in top %(value)s%(percentSymbol)s", args);
|
|
29533
|
+
},
|
|
29534
|
+
});
|
|
29415
29535
|
function getNumberCriterionlocalizedValues(criterion, locale) {
|
|
29416
29536
|
return criterion.values.map((value) => {
|
|
29417
29537
|
return value !== undefined
|
|
@@ -29433,6 +29553,10 @@ function checkValueIsNumber(value) {
|
|
|
29433
29553
|
const valueAsNumber = tryToNumber(value, DEFAULT_LOCALE);
|
|
29434
29554
|
return valueAsNumber !== undefined;
|
|
29435
29555
|
}
|
|
29556
|
+
function checkValueIsPositiveNumber(value) {
|
|
29557
|
+
const valueAsNumber = tryToNumber(value, DEFAULT_LOCALE);
|
|
29558
|
+
return valueAsNumber !== undefined && valueAsNumber > 0;
|
|
29559
|
+
}
|
|
29436
29560
|
|
|
29437
29561
|
// -----------------------------------------------------------------------------
|
|
29438
29562
|
// Constants
|
|
@@ -39763,6 +39887,10 @@ class EvaluationConditionalFormatPlugin extends CoreViewPlugin {
|
|
|
39763
39887
|
break;
|
|
39764
39888
|
case "CellIsRule":
|
|
39765
39889
|
const formulas = cf.rule.values.map((value) => value.startsWith("=") ? compile(value) : undefined);
|
|
39890
|
+
const evaluator = criterionEvaluatorRegistry.get(cf.rule.operator);
|
|
39891
|
+
const criterion = { ...cf.rule, type: cf.rule.operator };
|
|
39892
|
+
const ranges = cf.ranges.map((xc) => this.getters.getRangeFromSheetXC(sheetId, xc));
|
|
39893
|
+
const preComputedCriterion = evaluator.preComputeCriterion?.(criterion, ranges, this.getters);
|
|
39766
39894
|
for (const ref of cf.ranges) {
|
|
39767
39895
|
const zone = this.getters.getRangeFromSheetXC(sheetId, ref).zone;
|
|
39768
39896
|
for (let row = zone.top; row <= zone.bottom; row++) {
|
|
@@ -39775,7 +39903,7 @@ class EvaluationConditionalFormatPlugin extends CoreViewPlugin {
|
|
|
39775
39903
|
}
|
|
39776
39904
|
return value;
|
|
39777
39905
|
});
|
|
39778
|
-
if (this.getRuleResultForTarget(target, { ...cf.rule, values })) {
|
|
39906
|
+
if (this.getRuleResultForTarget(target, { ...cf.rule, values }, preComputedCriterion)) {
|
|
39779
39907
|
if (!computedStyle[col])
|
|
39780
39908
|
computedStyle[col] = [];
|
|
39781
39909
|
// we must combine all the properties of all the CF rules applied to the given cell
|
|
@@ -39938,7 +40066,7 @@ class EvaluationConditionalFormatPlugin extends CoreViewPlugin {
|
|
|
39938
40066
|
}
|
|
39939
40067
|
}
|
|
39940
40068
|
}
|
|
39941
|
-
getRuleResultForTarget(target, rule) {
|
|
40069
|
+
getRuleResultForTarget(target, rule, preComputedCriterion) {
|
|
39942
40070
|
const cell = this.getters.getEvaluatedCell(target);
|
|
39943
40071
|
if (cell.type === CellValueType.error) {
|
|
39944
40072
|
return false;
|
|
@@ -39955,11 +40083,12 @@ class EvaluationConditionalFormatPlugin extends CoreViewPlugin {
|
|
|
39955
40083
|
return false;
|
|
39956
40084
|
}
|
|
39957
40085
|
const evaluatedCriterion = {
|
|
40086
|
+
...rule,
|
|
39958
40087
|
type: rule.operator,
|
|
39959
40088
|
values: evaluatedCriterionValues.map(toScalar),
|
|
39960
40089
|
dateValue: rule.dateValue || "exactDate",
|
|
39961
40090
|
};
|
|
39962
|
-
return evaluator.isValueValid(cell.value ?? "", evaluatedCriterion,
|
|
40091
|
+
return evaluator.isValueValid(cell.value ?? "", evaluatedCriterion, preComputedCriterion);
|
|
39963
40092
|
}
|
|
39964
40093
|
}
|
|
39965
40094
|
|
|
@@ -39976,17 +40105,20 @@ class EvaluationDataValidationPlugin extends CoreViewPlugin {
|
|
|
39976
40105
|
"isDataValidationInvalid",
|
|
39977
40106
|
];
|
|
39978
40107
|
validationResults = {};
|
|
40108
|
+
criterionPreComputeResult = {};
|
|
39979
40109
|
handle(cmd) {
|
|
39980
40110
|
if (invalidateEvaluationCommands.has(cmd.type) ||
|
|
39981
40111
|
cmd.type === "EVALUATE_CELLS" ||
|
|
39982
40112
|
(cmd.type === "UPDATE_CELL" && ("content" in cmd || "format" in cmd))) {
|
|
39983
40113
|
this.validationResults = {};
|
|
40114
|
+
this.criterionPreComputeResult = {};
|
|
39984
40115
|
return;
|
|
39985
40116
|
}
|
|
39986
40117
|
switch (cmd.type) {
|
|
39987
40118
|
case "ADD_DATA_VALIDATION_RULE":
|
|
39988
40119
|
case "REMOVE_DATA_VALIDATION_RULE":
|
|
39989
40120
|
delete this.validationResults[cmd.sheetId];
|
|
40121
|
+
delete this.criterionPreComputeResult[cmd.sheetId];
|
|
39990
40122
|
break;
|
|
39991
40123
|
}
|
|
39992
40124
|
}
|
|
@@ -40129,7 +40261,15 @@ class EvaluationDataValidationPlugin extends CoreViewPlugin {
|
|
|
40129
40261
|
return undefined;
|
|
40130
40262
|
}
|
|
40131
40263
|
const evaluatedCriterion = { ...criterion, values: evaluatedCriterionValues.map(toScalar) };
|
|
40132
|
-
if (
|
|
40264
|
+
if (!this.criterionPreComputeResult[sheetId]) {
|
|
40265
|
+
this.criterionPreComputeResult[sheetId] = {};
|
|
40266
|
+
}
|
|
40267
|
+
let preComputedCriterion = this.criterionPreComputeResult[sheetId][rule.id];
|
|
40268
|
+
if (preComputedCriterion === undefined) {
|
|
40269
|
+
preComputedCriterion = evaluator.preComputeCriterion?.(rule.criterion, rule.ranges, this.getters);
|
|
40270
|
+
this.criterionPreComputeResult[sheetId][rule.id] = preComputedCriterion;
|
|
40271
|
+
}
|
|
40272
|
+
if (evaluator.isValueValid(cellValue, evaluatedCriterion, preComputedCriterion)) {
|
|
40133
40273
|
return undefined;
|
|
40134
40274
|
}
|
|
40135
40275
|
return evaluator.getErrorString(evaluatedCriterion, this.getters, sheetId);
|
|
@@ -45461,6 +45601,7 @@ class FilterEvaluationPlugin extends UIPlugin {
|
|
|
45461
45601
|
if (filterValue.type === "none")
|
|
45462
45602
|
continue;
|
|
45463
45603
|
const evaluator = criterionEvaluatorRegistry.get(filterValue.type);
|
|
45604
|
+
const preComputedCriterion = evaluator.preComputeCriterion?.(filterValue, [filter.filteredRange], this.getters);
|
|
45464
45605
|
const evaluatedCriterionValues = filterValue.values.map((value) => {
|
|
45465
45606
|
if (!value.startsWith("=")) {
|
|
45466
45607
|
return parseLiteral(value, DEFAULT_LOCALE);
|
|
@@ -45478,7 +45619,7 @@ class FilterEvaluationPlugin extends UIPlugin {
|
|
|
45478
45619
|
for (let row = filteredZone.top; row <= filteredZone.bottom; row++) {
|
|
45479
45620
|
const position = { sheetId, col: filter.col, row };
|
|
45480
45621
|
const value = this.getters.getEvaluatedCell(position).value ?? "";
|
|
45481
|
-
if (!evaluator.isValueValid(value, evaluatedCriterion,
|
|
45622
|
+
if (!evaluator.isValueValid(value, evaluatedCriterion, preComputedCriterion)) {
|
|
45482
45623
|
hiddenRows.add(row);
|
|
45483
45624
|
}
|
|
45484
45625
|
}
|
|
@@ -49619,6 +49760,8 @@ function cellRuleFormula(ranges, rule) {
|
|
|
49619
49760
|
case undefined:
|
|
49620
49761
|
throw new Error("dateValue should be defined");
|
|
49621
49762
|
}
|
|
49763
|
+
case "top10":
|
|
49764
|
+
return [];
|
|
49622
49765
|
}
|
|
49623
49766
|
}
|
|
49624
49767
|
function cellRuleTypeAttributes(rule) {
|
|
@@ -49651,6 +49794,14 @@ function cellRuleTypeAttributes(rule) {
|
|
|
49651
49794
|
case "dateIs":
|
|
49652
49795
|
case "customFormula":
|
|
49653
49796
|
return [["type", "expression"]];
|
|
49797
|
+
case "top10": {
|
|
49798
|
+
return [
|
|
49799
|
+
["type", "top10"],
|
|
49800
|
+
["rank", rule.values[0]],
|
|
49801
|
+
["percent", rule.isPercent ? "1" : "0"],
|
|
49802
|
+
["bottom", rule.isBottom ? "1" : "0"],
|
|
49803
|
+
];
|
|
49804
|
+
}
|
|
49654
49805
|
}
|
|
49655
49806
|
}
|
|
49656
49807
|
function addDataBarRule(cf, rule) {
|
|
@@ -51523,5 +51674,5 @@ export { BadExpressionError, BasePlugin, CellErrorType, CircularDependencyError,
|
|
|
51523
51674
|
|
|
51524
51675
|
|
|
51525
51676
|
__info__.version = "19.1.0-alpha.3";
|
|
51526
|
-
__info__.date = "
|
|
51527
|
-
__info__.hash = "
|
|
51677
|
+
__info__.date = "2026-01-07T16:20:57.293Z";
|
|
51678
|
+
__info__.hash = "ac2fa3e";
|