@odoo/o-spreadsheet 18.0.9 → 18.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/o-spreadsheet.cjs.js +694 -317
- package/dist/o-spreadsheet.d.ts +30 -16
- package/dist/o-spreadsheet.esm.js +694 -317
- package/dist/o-spreadsheet.iife.js +694 -317
- package/dist/o-spreadsheet.iife.min.js +372 -345
- package/dist/o_spreadsheet.xml +11 -5
- 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 18.0.
|
|
6
|
-
* @date 2025-01-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 18.0.11
|
|
6
|
+
* @date 2025-01-27T10:08:13.567Z
|
|
7
|
+
* @hash e8c6bd1
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, useState, onPatched, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
|
|
@@ -4209,15 +4209,18 @@ function dichotomicSearch(data, target, mode, sortOrder, rangeLength, getValueIn
|
|
|
4209
4209
|
let currentIndex;
|
|
4210
4210
|
let currentVal;
|
|
4211
4211
|
let currentType;
|
|
4212
|
+
const getValue = sortOrder === "desc"
|
|
4213
|
+
? (i) => normalizeValue(getValueInData(data, rangeLength - i - 1))
|
|
4214
|
+
: (i) => normalizeValue(getValueInData(data, i));
|
|
4212
4215
|
while (indexRight - indexLeft >= 0) {
|
|
4213
4216
|
indexMedian = Math.floor((indexLeft + indexRight) / 2);
|
|
4214
4217
|
currentIndex = indexMedian;
|
|
4215
|
-
currentVal =
|
|
4218
|
+
currentVal = getValue(currentIndex);
|
|
4216
4219
|
currentType = typeof currentVal;
|
|
4217
4220
|
// 1 - linear search to find value with the same type
|
|
4218
4221
|
while (indexLeft < currentIndex && targetType !== currentType) {
|
|
4219
4222
|
currentIndex--;
|
|
4220
|
-
currentVal =
|
|
4223
|
+
currentVal = getValue(currentIndex);
|
|
4221
4224
|
currentType = typeof currentVal;
|
|
4222
4225
|
}
|
|
4223
4226
|
if (currentType !== targetType || currentVal === undefined || currentVal === null) {
|
|
@@ -4233,8 +4236,7 @@ function dichotomicSearch(data, target, mode, sortOrder, rangeLength, getValueIn
|
|
|
4233
4236
|
if (matchVal === undefined ||
|
|
4234
4237
|
matchVal === null ||
|
|
4235
4238
|
matchVal < currentVal ||
|
|
4236
|
-
(matchVal === currentVal &&
|
|
4237
|
-
(matchVal === currentVal && sortOrder === "desc" && matchValIndex > currentIndex)) {
|
|
4239
|
+
(matchVal === currentVal && matchValIndex < currentIndex)) {
|
|
4238
4240
|
matchVal = currentVal;
|
|
4239
4241
|
matchValIndex = currentIndex;
|
|
4240
4242
|
}
|
|
@@ -4242,15 +4244,13 @@ function dichotomicSearch(data, target, mode, sortOrder, rangeLength, getValueIn
|
|
|
4242
4244
|
else if (mode === "nextGreater" && currentVal >= _target) {
|
|
4243
4245
|
if (matchVal === undefined ||
|
|
4244
4246
|
matchVal > currentVal ||
|
|
4245
|
-
(matchVal === currentVal &&
|
|
4246
|
-
(matchVal === currentVal && sortOrder === "desc" && matchValIndex > currentIndex)) {
|
|
4247
|
+
(matchVal === currentVal && matchValIndex < currentIndex)) {
|
|
4247
4248
|
matchVal = currentVal;
|
|
4248
4249
|
matchValIndex = currentIndex;
|
|
4249
4250
|
}
|
|
4250
4251
|
}
|
|
4251
4252
|
// 3 - give new indexes for the Binary search
|
|
4252
|
-
if ((
|
|
4253
|
-
(sortOrder === "desc" && currentVal <= _target)) {
|
|
4253
|
+
if (currentVal > _target || (mode === "strict" && currentVal === _target)) {
|
|
4254
4254
|
indexRight = currentIndex - 1;
|
|
4255
4255
|
}
|
|
4256
4256
|
else {
|
|
@@ -4258,7 +4258,10 @@ function dichotomicSearch(data, target, mode, sortOrder, rangeLength, getValueIn
|
|
|
4258
4258
|
}
|
|
4259
4259
|
}
|
|
4260
4260
|
// note that valMinIndex could be 0
|
|
4261
|
-
|
|
4261
|
+
if (matchValIndex === undefined) {
|
|
4262
|
+
return -1;
|
|
4263
|
+
}
|
|
4264
|
+
return sortOrder === "desc" ? rangeLength - matchValIndex - 1 : matchValIndex;
|
|
4262
4265
|
}
|
|
4263
4266
|
/**
|
|
4264
4267
|
* Perform a linear search and return the index of the match.
|
|
@@ -4390,47 +4393,83 @@ function isDataNonEmpty(data) {
|
|
|
4390
4393
|
return true;
|
|
4391
4394
|
}
|
|
4392
4395
|
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4397
|
-
|
|
4398
|
-
case "yesterday":
|
|
4399
|
-
return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 1)));
|
|
4400
|
-
case "tomorrow":
|
|
4401
|
-
return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() + 1)));
|
|
4402
|
-
case "lastWeek":
|
|
4403
|
-
return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 7)));
|
|
4404
|
-
case "lastMonth":
|
|
4405
|
-
return jsDateToNumber(DateTime.fromTimestamp(today.setMonth(today.getMonth() - 1)));
|
|
4406
|
-
case "lastYear":
|
|
4407
|
-
return jsDateToNumber(DateTime.fromTimestamp(today.setFullYear(today.getFullYear() - 1)));
|
|
4408
|
-
}
|
|
4396
|
+
/**
|
|
4397
|
+
* Add the `https` prefix to the url if it's missing
|
|
4398
|
+
*/
|
|
4399
|
+
function withHttps(url) {
|
|
4400
|
+
return !/^https?:\/\//i.test(url) ? `https://${url}` : url;
|
|
4409
4401
|
}
|
|
4410
|
-
|
|
4411
|
-
function
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4402
|
+
const urlRegistry = new Registry();
|
|
4403
|
+
function createWebLink(url, label) {
|
|
4404
|
+
url = withHttps(url);
|
|
4405
|
+
return {
|
|
4406
|
+
url,
|
|
4407
|
+
label: label || url,
|
|
4408
|
+
isExternal: true,
|
|
4409
|
+
isUrlEditable: true,
|
|
4410
|
+
};
|
|
4416
4411
|
}
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4412
|
+
urlRegistry.add("sheet_URL", {
|
|
4413
|
+
match: (url) => isSheetUrl(url),
|
|
4414
|
+
createLink: (url, label) => {
|
|
4415
|
+
return {
|
|
4416
|
+
label,
|
|
4417
|
+
url,
|
|
4418
|
+
isExternal: false,
|
|
4419
|
+
isUrlEditable: false,
|
|
4420
|
+
};
|
|
4421
|
+
},
|
|
4422
|
+
urlRepresentation(url, getters) {
|
|
4423
|
+
const sheetId = parseSheetUrl(url);
|
|
4424
|
+
return getters.tryGetSheetName(sheetId) || _t("Invalid sheet");
|
|
4425
|
+
},
|
|
4426
|
+
open(url, env) {
|
|
4427
|
+
const sheetId = parseSheetUrl(url);
|
|
4428
|
+
const result = env.model.dispatch("ACTIVATE_SHEET", {
|
|
4429
|
+
sheetIdFrom: env.model.getters.getActiveSheetId(),
|
|
4430
|
+
sheetIdTo: sheetId,
|
|
4431
|
+
});
|
|
4432
|
+
if (result.isCancelledBecause("SheetIsHidden" /* CommandResult.SheetIsHidden */)) {
|
|
4433
|
+
env.notifyUser({
|
|
4434
|
+
type: "warning",
|
|
4435
|
+
sticky: false,
|
|
4436
|
+
text: _t("Cannot open the link because the linked sheet is hidden."),
|
|
4437
|
+
});
|
|
4438
|
+
}
|
|
4439
|
+
},
|
|
4440
|
+
sequence: 0,
|
|
4441
|
+
});
|
|
4442
|
+
const WebUrlSpec = {
|
|
4443
|
+
createLink: createWebLink,
|
|
4444
|
+
match: (url) => isWebLink(url),
|
|
4445
|
+
open: (url) => window.open(url, "_blank"),
|
|
4446
|
+
urlRepresentation: (url) => url,
|
|
4447
|
+
sequence: 0,
|
|
4448
|
+
};
|
|
4449
|
+
function findMatchingSpec(url) {
|
|
4450
|
+
return (urlRegistry
|
|
4451
|
+
.getAll()
|
|
4452
|
+
.sort((a, b) => a.sequence - b.sequence)
|
|
4453
|
+
.find((urlType) => urlType.match(url)) || WebUrlSpec);
|
|
4420
4454
|
}
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4455
|
+
function urlRepresentation(link, getters) {
|
|
4456
|
+
return findMatchingSpec(link.url).urlRepresentation(link.url, getters);
|
|
4457
|
+
}
|
|
4458
|
+
function openLink(link, env) {
|
|
4459
|
+
findMatchingSpec(link.url).open(link.url, env);
|
|
4460
|
+
}
|
|
4461
|
+
function detectLink(value) {
|
|
4462
|
+
if (typeof value !== "string") {
|
|
4463
|
+
return undefined;
|
|
4464
|
+
}
|
|
4465
|
+
if (isMarkdownLink(value)) {
|
|
4466
|
+
const { label, url } = parseMarkdownLink(value);
|
|
4467
|
+
return findMatchingSpec(url).createLink(url, label);
|
|
4468
|
+
}
|
|
4469
|
+
else if (isWebLink(value)) {
|
|
4470
|
+
return createWebLink(value);
|
|
4471
|
+
}
|
|
4472
|
+
return undefined;
|
|
4434
4473
|
}
|
|
4435
4474
|
|
|
4436
4475
|
function tokenizeFormat(str) {
|
|
@@ -5492,6 +5531,193 @@ function isTextFormat(format) {
|
|
|
5492
5531
|
}
|
|
5493
5532
|
}
|
|
5494
5533
|
|
|
5534
|
+
function evaluateLiteral(literalCell, localeFormat) {
|
|
5535
|
+
const value = isTextFormat(localeFormat.format) ? literalCell.content : literalCell.parsedValue;
|
|
5536
|
+
const functionResult = { value, format: localeFormat.format };
|
|
5537
|
+
return createEvaluatedCell(functionResult, localeFormat.locale);
|
|
5538
|
+
}
|
|
5539
|
+
function parseLiteral(content, locale) {
|
|
5540
|
+
if (content.startsWith("=")) {
|
|
5541
|
+
throw new Error(`Cannot parse "${content}" because it's not a literal value. It's a formula`);
|
|
5542
|
+
}
|
|
5543
|
+
if (content === "") {
|
|
5544
|
+
return null;
|
|
5545
|
+
}
|
|
5546
|
+
if (isNumber(content, DEFAULT_LOCALE)) {
|
|
5547
|
+
return parseNumber(content, DEFAULT_LOCALE);
|
|
5548
|
+
}
|
|
5549
|
+
const internalDate = parseDateTime(content, locale);
|
|
5550
|
+
if (internalDate) {
|
|
5551
|
+
return internalDate.value;
|
|
5552
|
+
}
|
|
5553
|
+
if (isBoolean(content)) {
|
|
5554
|
+
return content.toUpperCase() === "TRUE" ? true : false;
|
|
5555
|
+
}
|
|
5556
|
+
return content;
|
|
5557
|
+
}
|
|
5558
|
+
function createEvaluatedCell(functionResult, locale = DEFAULT_LOCALE, cell) {
|
|
5559
|
+
const link = detectLink(functionResult.value);
|
|
5560
|
+
if (!link) {
|
|
5561
|
+
return _createEvaluatedCell(functionResult, locale, cell);
|
|
5562
|
+
}
|
|
5563
|
+
const value = parseLiteral(link.label, locale);
|
|
5564
|
+
const format = functionResult.format ||
|
|
5565
|
+
(typeof value === "number"
|
|
5566
|
+
? detectDateFormat(link.label, locale) || detectNumberFormat(link.label)
|
|
5567
|
+
: undefined);
|
|
5568
|
+
const linkPayload = {
|
|
5569
|
+
value,
|
|
5570
|
+
format,
|
|
5571
|
+
};
|
|
5572
|
+
return {
|
|
5573
|
+
..._createEvaluatedCell(linkPayload, locale, cell),
|
|
5574
|
+
link,
|
|
5575
|
+
};
|
|
5576
|
+
}
|
|
5577
|
+
function _createEvaluatedCell(functionResult, locale, cell) {
|
|
5578
|
+
let { value, format, message } = functionResult;
|
|
5579
|
+
format = cell?.format || format;
|
|
5580
|
+
const formattedValue = formatValue(value, { format, locale });
|
|
5581
|
+
if (isEvaluationError(value)) {
|
|
5582
|
+
return errorCell(value, message);
|
|
5583
|
+
}
|
|
5584
|
+
if (isTextFormat(format)) {
|
|
5585
|
+
// TO DO:
|
|
5586
|
+
// with the next line, the value of the cell is transformed depending on the format.
|
|
5587
|
+
// This shouldn't happen, by doing this, the formulas handling numbers are not able
|
|
5588
|
+
// to interpret the value as a number.
|
|
5589
|
+
return textCell(toString(value), format, formattedValue);
|
|
5590
|
+
}
|
|
5591
|
+
if (value === null) {
|
|
5592
|
+
return emptyCell(format);
|
|
5593
|
+
}
|
|
5594
|
+
if (typeof value === "number") {
|
|
5595
|
+
if (isDateTimeFormat(format || "")) {
|
|
5596
|
+
return dateTimeCell(value, format, formattedValue);
|
|
5597
|
+
}
|
|
5598
|
+
return numberCell(value, format, formattedValue);
|
|
5599
|
+
}
|
|
5600
|
+
if (typeof value === "boolean") {
|
|
5601
|
+
return booleanCell(value, format, formattedValue);
|
|
5602
|
+
}
|
|
5603
|
+
return textCell(value, format, formattedValue);
|
|
5604
|
+
}
|
|
5605
|
+
function textCell(value, format, formattedValue) {
|
|
5606
|
+
return {
|
|
5607
|
+
value,
|
|
5608
|
+
format,
|
|
5609
|
+
formattedValue,
|
|
5610
|
+
type: CellValueType.text,
|
|
5611
|
+
isAutoSummable: true,
|
|
5612
|
+
defaultAlign: "left",
|
|
5613
|
+
};
|
|
5614
|
+
}
|
|
5615
|
+
function numberCell(value, format, formattedValue) {
|
|
5616
|
+
return {
|
|
5617
|
+
value: value || 0, // necessary to avoid "-0" and NaN values,
|
|
5618
|
+
format,
|
|
5619
|
+
formattedValue,
|
|
5620
|
+
type: CellValueType.number,
|
|
5621
|
+
isAutoSummable: true,
|
|
5622
|
+
defaultAlign: "right",
|
|
5623
|
+
};
|
|
5624
|
+
}
|
|
5625
|
+
const emptyCell = memoize(function emptyCell(format) {
|
|
5626
|
+
return {
|
|
5627
|
+
value: null,
|
|
5628
|
+
format,
|
|
5629
|
+
formattedValue: "",
|
|
5630
|
+
type: CellValueType.empty,
|
|
5631
|
+
isAutoSummable: true,
|
|
5632
|
+
defaultAlign: "left",
|
|
5633
|
+
};
|
|
5634
|
+
});
|
|
5635
|
+
function dateTimeCell(value, format, formattedValue) {
|
|
5636
|
+
return {
|
|
5637
|
+
value,
|
|
5638
|
+
format,
|
|
5639
|
+
formattedValue,
|
|
5640
|
+
type: CellValueType.number,
|
|
5641
|
+
isAutoSummable: false,
|
|
5642
|
+
defaultAlign: "right",
|
|
5643
|
+
};
|
|
5644
|
+
}
|
|
5645
|
+
function booleanCell(value, format, formattedValue) {
|
|
5646
|
+
return {
|
|
5647
|
+
value,
|
|
5648
|
+
format,
|
|
5649
|
+
formattedValue,
|
|
5650
|
+
type: CellValueType.boolean,
|
|
5651
|
+
isAutoSummable: false,
|
|
5652
|
+
defaultAlign: "center",
|
|
5653
|
+
};
|
|
5654
|
+
}
|
|
5655
|
+
function errorCell(value, message) {
|
|
5656
|
+
return {
|
|
5657
|
+
value,
|
|
5658
|
+
formattedValue: value,
|
|
5659
|
+
message,
|
|
5660
|
+
type: CellValueType.error,
|
|
5661
|
+
isAutoSummable: false,
|
|
5662
|
+
defaultAlign: "center",
|
|
5663
|
+
};
|
|
5664
|
+
}
|
|
5665
|
+
|
|
5666
|
+
function toCriterionDateNumber(dateValue) {
|
|
5667
|
+
const today = DateTime.now();
|
|
5668
|
+
switch (dateValue) {
|
|
5669
|
+
case "today":
|
|
5670
|
+
return jsDateToNumber(today);
|
|
5671
|
+
case "yesterday":
|
|
5672
|
+
return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 1)));
|
|
5673
|
+
case "tomorrow":
|
|
5674
|
+
return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() + 1)));
|
|
5675
|
+
case "lastWeek":
|
|
5676
|
+
return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 7)));
|
|
5677
|
+
case "lastMonth":
|
|
5678
|
+
return jsDateToNumber(DateTime.fromTimestamp(today.setMonth(today.getMonth() - 1)));
|
|
5679
|
+
case "lastYear":
|
|
5680
|
+
return jsDateToNumber(DateTime.fromTimestamp(today.setFullYear(today.getFullYear() - 1)));
|
|
5681
|
+
}
|
|
5682
|
+
}
|
|
5683
|
+
/** Get all the dates values of a criterion converted to numbers, converting date values such as "today" to actual dates */
|
|
5684
|
+
function getDateNumberCriterionValues(criterion, locale) {
|
|
5685
|
+
if ("dateValue" in criterion && criterion.dateValue !== "exactDate") {
|
|
5686
|
+
return [toCriterionDateNumber(criterion.dateValue)];
|
|
5687
|
+
}
|
|
5688
|
+
return criterion.values.map((value) => valueToDateNumber(value, locale));
|
|
5689
|
+
}
|
|
5690
|
+
/** Convert the criterion values to numbers. Return undefined values if they cannot be converted to numbers. */
|
|
5691
|
+
function getCriterionValuesAsNumber(criterion, locale) {
|
|
5692
|
+
return criterion.values.map((value) => tryToNumber(value, locale));
|
|
5693
|
+
}
|
|
5694
|
+
function getDateCriterionFormattedValues(values, locale) {
|
|
5695
|
+
return values.map((valueStr) => {
|
|
5696
|
+
if (valueStr.startsWith("=")) {
|
|
5697
|
+
return valueStr;
|
|
5698
|
+
}
|
|
5699
|
+
const value = parseLiteral(valueStr, locale);
|
|
5700
|
+
if (typeof value === "number") {
|
|
5701
|
+
return formatValue(value, { format: locale.dateFormat, locale });
|
|
5702
|
+
}
|
|
5703
|
+
return "";
|
|
5704
|
+
});
|
|
5705
|
+
}
|
|
5706
|
+
|
|
5707
|
+
const MAX_DELAY = 140;
|
|
5708
|
+
const MIN_DELAY = 20;
|
|
5709
|
+
const ACCELERATION = 0.035;
|
|
5710
|
+
/**
|
|
5711
|
+
* Decreasing exponential function used to determine the "speed" of edge-scrolling
|
|
5712
|
+
* as the timeout delay.
|
|
5713
|
+
*
|
|
5714
|
+
* Returns a timeout delay in milliseconds.
|
|
5715
|
+
*/
|
|
5716
|
+
function scrollDelay(value) {
|
|
5717
|
+
// decreasing exponential from MAX_DELAY to MIN_DELAY
|
|
5718
|
+
return MIN_DELAY + (MAX_DELAY - MIN_DELAY) * Math.exp(-ACCELERATION * (value - 1));
|
|
5719
|
+
}
|
|
5720
|
+
|
|
5495
5721
|
class RangeImpl {
|
|
5496
5722
|
getSheetSize;
|
|
5497
5723
|
_zone;
|
|
@@ -22093,217 +22319,6 @@ autoCompleteProviders.add("sheet_names", {
|
|
|
22093
22319
|
},
|
|
22094
22320
|
});
|
|
22095
22321
|
|
|
22096
|
-
/**
|
|
22097
|
-
* Add the `https` prefix to the url if it's missing
|
|
22098
|
-
*/
|
|
22099
|
-
function withHttps(url) {
|
|
22100
|
-
return !/^https?:\/\//i.test(url) ? `https://${url}` : url;
|
|
22101
|
-
}
|
|
22102
|
-
const urlRegistry = new Registry();
|
|
22103
|
-
function createWebLink(url, label) {
|
|
22104
|
-
url = withHttps(url);
|
|
22105
|
-
return {
|
|
22106
|
-
url,
|
|
22107
|
-
label: label || url,
|
|
22108
|
-
isExternal: true,
|
|
22109
|
-
isUrlEditable: true,
|
|
22110
|
-
};
|
|
22111
|
-
}
|
|
22112
|
-
urlRegistry.add("sheet_URL", {
|
|
22113
|
-
match: (url) => isSheetUrl(url),
|
|
22114
|
-
createLink: (url, label) => {
|
|
22115
|
-
return {
|
|
22116
|
-
label,
|
|
22117
|
-
url,
|
|
22118
|
-
isExternal: false,
|
|
22119
|
-
isUrlEditable: false,
|
|
22120
|
-
};
|
|
22121
|
-
},
|
|
22122
|
-
urlRepresentation(url, getters) {
|
|
22123
|
-
const sheetId = parseSheetUrl(url);
|
|
22124
|
-
return getters.tryGetSheetName(sheetId) || _t("Invalid sheet");
|
|
22125
|
-
},
|
|
22126
|
-
open(url, env) {
|
|
22127
|
-
const sheetId = parseSheetUrl(url);
|
|
22128
|
-
const result = env.model.dispatch("ACTIVATE_SHEET", {
|
|
22129
|
-
sheetIdFrom: env.model.getters.getActiveSheetId(),
|
|
22130
|
-
sheetIdTo: sheetId,
|
|
22131
|
-
});
|
|
22132
|
-
if (result.isCancelledBecause("SheetIsHidden" /* CommandResult.SheetIsHidden */)) {
|
|
22133
|
-
env.notifyUser({
|
|
22134
|
-
type: "warning",
|
|
22135
|
-
sticky: false,
|
|
22136
|
-
text: _t("Cannot open the link because the linked sheet is hidden."),
|
|
22137
|
-
});
|
|
22138
|
-
}
|
|
22139
|
-
},
|
|
22140
|
-
sequence: 0,
|
|
22141
|
-
});
|
|
22142
|
-
const WebUrlSpec = {
|
|
22143
|
-
createLink: createWebLink,
|
|
22144
|
-
match: (url) => isWebLink(url),
|
|
22145
|
-
open: (url) => window.open(url, "_blank"),
|
|
22146
|
-
urlRepresentation: (url) => url,
|
|
22147
|
-
sequence: 0,
|
|
22148
|
-
};
|
|
22149
|
-
function findMatchingSpec(url) {
|
|
22150
|
-
return (urlRegistry
|
|
22151
|
-
.getAll()
|
|
22152
|
-
.sort((a, b) => a.sequence - b.sequence)
|
|
22153
|
-
.find((urlType) => urlType.match(url)) || WebUrlSpec);
|
|
22154
|
-
}
|
|
22155
|
-
function urlRepresentation(link, getters) {
|
|
22156
|
-
return findMatchingSpec(link.url).urlRepresentation(link.url, getters);
|
|
22157
|
-
}
|
|
22158
|
-
function openLink(link, env) {
|
|
22159
|
-
findMatchingSpec(link.url).open(link.url, env);
|
|
22160
|
-
}
|
|
22161
|
-
function detectLink(value) {
|
|
22162
|
-
if (typeof value !== "string") {
|
|
22163
|
-
return undefined;
|
|
22164
|
-
}
|
|
22165
|
-
if (isMarkdownLink(value)) {
|
|
22166
|
-
const { label, url } = parseMarkdownLink(value);
|
|
22167
|
-
return findMatchingSpec(url).createLink(url, label);
|
|
22168
|
-
}
|
|
22169
|
-
else if (isWebLink(value)) {
|
|
22170
|
-
return createWebLink(value);
|
|
22171
|
-
}
|
|
22172
|
-
return undefined;
|
|
22173
|
-
}
|
|
22174
|
-
|
|
22175
|
-
function evaluateLiteral(literalCell, localeFormat) {
|
|
22176
|
-
const value = isTextFormat(localeFormat.format) ? literalCell.content : literalCell.parsedValue;
|
|
22177
|
-
const functionResult = { value, format: localeFormat.format };
|
|
22178
|
-
return createEvaluatedCell(functionResult, localeFormat.locale);
|
|
22179
|
-
}
|
|
22180
|
-
function parseLiteral(content, locale) {
|
|
22181
|
-
if (content.startsWith("=")) {
|
|
22182
|
-
throw new Error(`Cannot parse "${content}" because it's not a literal value. It's a formula`);
|
|
22183
|
-
}
|
|
22184
|
-
if (content === "") {
|
|
22185
|
-
return null;
|
|
22186
|
-
}
|
|
22187
|
-
if (isNumber(content, DEFAULT_LOCALE)) {
|
|
22188
|
-
return parseNumber(content, DEFAULT_LOCALE);
|
|
22189
|
-
}
|
|
22190
|
-
const internalDate = parseDateTime(content, locale);
|
|
22191
|
-
if (internalDate) {
|
|
22192
|
-
return internalDate.value;
|
|
22193
|
-
}
|
|
22194
|
-
if (isBoolean(content)) {
|
|
22195
|
-
return content.toUpperCase() === "TRUE" ? true : false;
|
|
22196
|
-
}
|
|
22197
|
-
return content;
|
|
22198
|
-
}
|
|
22199
|
-
function createEvaluatedCell(functionResult, locale = DEFAULT_LOCALE, cell) {
|
|
22200
|
-
const link = detectLink(functionResult.value);
|
|
22201
|
-
if (!link) {
|
|
22202
|
-
return _createEvaluatedCell(functionResult, locale, cell);
|
|
22203
|
-
}
|
|
22204
|
-
const value = parseLiteral(link.label, locale);
|
|
22205
|
-
const format = functionResult.format ||
|
|
22206
|
-
(typeof value === "number"
|
|
22207
|
-
? detectDateFormat(link.label, locale) || detectNumberFormat(link.label)
|
|
22208
|
-
: undefined);
|
|
22209
|
-
const linkPayload = {
|
|
22210
|
-
value,
|
|
22211
|
-
format,
|
|
22212
|
-
};
|
|
22213
|
-
return {
|
|
22214
|
-
..._createEvaluatedCell(linkPayload, locale, cell),
|
|
22215
|
-
link,
|
|
22216
|
-
};
|
|
22217
|
-
}
|
|
22218
|
-
function _createEvaluatedCell(functionResult, locale, cell) {
|
|
22219
|
-
let { value, format, message } = functionResult;
|
|
22220
|
-
format = cell?.format || format;
|
|
22221
|
-
const formattedValue = formatValue(value, { format, locale });
|
|
22222
|
-
if (isEvaluationError(value)) {
|
|
22223
|
-
return errorCell(value, message);
|
|
22224
|
-
}
|
|
22225
|
-
if (isTextFormat(format)) {
|
|
22226
|
-
// TO DO:
|
|
22227
|
-
// with the next line, the value of the cell is transformed depending on the format.
|
|
22228
|
-
// This shouldn't happen, by doing this, the formulas handling numbers are not able
|
|
22229
|
-
// to interpret the value as a number.
|
|
22230
|
-
return textCell(toString(value), format, formattedValue);
|
|
22231
|
-
}
|
|
22232
|
-
if (value === null) {
|
|
22233
|
-
return emptyCell(format);
|
|
22234
|
-
}
|
|
22235
|
-
if (typeof value === "number") {
|
|
22236
|
-
if (isDateTimeFormat(format || "")) {
|
|
22237
|
-
return dateTimeCell(value, format, formattedValue);
|
|
22238
|
-
}
|
|
22239
|
-
return numberCell(value, format, formattedValue);
|
|
22240
|
-
}
|
|
22241
|
-
if (typeof value === "boolean") {
|
|
22242
|
-
return booleanCell(value, format, formattedValue);
|
|
22243
|
-
}
|
|
22244
|
-
return textCell(value, format, formattedValue);
|
|
22245
|
-
}
|
|
22246
|
-
function textCell(value, format, formattedValue) {
|
|
22247
|
-
return {
|
|
22248
|
-
value,
|
|
22249
|
-
format,
|
|
22250
|
-
formattedValue,
|
|
22251
|
-
type: CellValueType.text,
|
|
22252
|
-
isAutoSummable: true,
|
|
22253
|
-
defaultAlign: "left",
|
|
22254
|
-
};
|
|
22255
|
-
}
|
|
22256
|
-
function numberCell(value, format, formattedValue) {
|
|
22257
|
-
return {
|
|
22258
|
-
value: value || 0, // necessary to avoid "-0" and NaN values,
|
|
22259
|
-
format,
|
|
22260
|
-
formattedValue,
|
|
22261
|
-
type: CellValueType.number,
|
|
22262
|
-
isAutoSummable: true,
|
|
22263
|
-
defaultAlign: "right",
|
|
22264
|
-
};
|
|
22265
|
-
}
|
|
22266
|
-
const emptyCell = memoize(function emptyCell(format) {
|
|
22267
|
-
return {
|
|
22268
|
-
value: null,
|
|
22269
|
-
format,
|
|
22270
|
-
formattedValue: "",
|
|
22271
|
-
type: CellValueType.empty,
|
|
22272
|
-
isAutoSummable: true,
|
|
22273
|
-
defaultAlign: "left",
|
|
22274
|
-
};
|
|
22275
|
-
});
|
|
22276
|
-
function dateTimeCell(value, format, formattedValue) {
|
|
22277
|
-
return {
|
|
22278
|
-
value,
|
|
22279
|
-
format,
|
|
22280
|
-
formattedValue,
|
|
22281
|
-
type: CellValueType.number,
|
|
22282
|
-
isAutoSummable: false,
|
|
22283
|
-
defaultAlign: "right",
|
|
22284
|
-
};
|
|
22285
|
-
}
|
|
22286
|
-
function booleanCell(value, format, formattedValue) {
|
|
22287
|
-
return {
|
|
22288
|
-
value,
|
|
22289
|
-
format,
|
|
22290
|
-
formattedValue,
|
|
22291
|
-
type: CellValueType.boolean,
|
|
22292
|
-
isAutoSummable: false,
|
|
22293
|
-
defaultAlign: "center",
|
|
22294
|
-
};
|
|
22295
|
-
}
|
|
22296
|
-
function errorCell(value, message) {
|
|
22297
|
-
return {
|
|
22298
|
-
value,
|
|
22299
|
-
formattedValue: value,
|
|
22300
|
-
message,
|
|
22301
|
-
type: CellValueType.error,
|
|
22302
|
-
isAutoSummable: false,
|
|
22303
|
-
defaultAlign: "center",
|
|
22304
|
-
};
|
|
22305
|
-
}
|
|
22306
|
-
|
|
22307
22322
|
/**
|
|
22308
22323
|
* An AutofillModifierImplementation is used to describe how to handle a
|
|
22309
22324
|
* AutofillModifier.
|
|
@@ -23449,6 +23464,10 @@ var WarningTypes;
|
|
|
23449
23464
|
WarningTypes["CfIconSetEmptyIconNotSupported"] = "IconSets with empty icons";
|
|
23450
23465
|
WarningTypes["BadlyFormattedHyperlink"] = "Badly formatted hyperlink";
|
|
23451
23466
|
WarningTypes["NumFmtIdNotSupported"] = "Number format";
|
|
23467
|
+
WarningTypes["TimeDataValidationNotSupported"] = "Time data validation rules";
|
|
23468
|
+
WarningTypes["TextLengthDataValidationNotSupported"] = "Text length data validation rules";
|
|
23469
|
+
WarningTypes["WholeNumberDataValidationNotSupported"] = "Whole number data validation rules";
|
|
23470
|
+
WarningTypes["NotEqualDateDataValidationNotSupported"] = "Not equal date data validation rules";
|
|
23452
23471
|
})(WarningTypes || (WarningTypes = {}));
|
|
23453
23472
|
class XLSXImportWarningManager {
|
|
23454
23473
|
_parsingWarnings = new Set();
|
|
@@ -23827,6 +23846,25 @@ const IMAGE_EXTENSION_TO_MIMETYPE_MAPPING = {
|
|
|
23827
23846
|
webp: "image/webp",
|
|
23828
23847
|
jpg: "image/jpeg",
|
|
23829
23848
|
};
|
|
23849
|
+
const XLSX_DV_DECIMAL_OPERATOR_MAPPING = {
|
|
23850
|
+
between: "isBetween",
|
|
23851
|
+
notBetween: "isNotBetween",
|
|
23852
|
+
equal: "isEqual",
|
|
23853
|
+
notEqual: "isNotEqual",
|
|
23854
|
+
greaterThan: "isGreaterThan",
|
|
23855
|
+
greaterThanOrEqual: "isGreaterOrEqualTo",
|
|
23856
|
+
lessThan: "isLessThan",
|
|
23857
|
+
lessThanOrEqual: "isLessOrEqualTo",
|
|
23858
|
+
};
|
|
23859
|
+
const XLSX_DV_DATE_OPERATOR_TO_DV_TYPE_MAPPING = {
|
|
23860
|
+
between: "dateIsBetween",
|
|
23861
|
+
notBetween: "dateIsNotBetween",
|
|
23862
|
+
equal: "dateIs",
|
|
23863
|
+
greaterThan: "dateIsAfter",
|
|
23864
|
+
greaterThanOrEqual: "dateIsOnOrAfter",
|
|
23865
|
+
lessThan: "dateIsBefore",
|
|
23866
|
+
lessThanOrEqual: "dateIsOnOrBefore",
|
|
23867
|
+
};
|
|
23830
23868
|
|
|
23831
23869
|
/**
|
|
23832
23870
|
* Most of the functions could stay private, but are exported for testing purposes
|
|
@@ -24596,6 +24634,20 @@ function getRowPosition(rowIndex, sheetData) {
|
|
|
24596
24634
|
}
|
|
24597
24635
|
return position / HEIGHT_FACTOR;
|
|
24598
24636
|
}
|
|
24637
|
+
/**
|
|
24638
|
+
* Convert the o-spreadsheet data validation decimal
|
|
24639
|
+
* criterion type to the corresponding excel operator.
|
|
24640
|
+
*/
|
|
24641
|
+
function convertDecimalCriterionTypeToExcelOperator(operator) {
|
|
24642
|
+
return Object.keys(XLSX_DV_DECIMAL_OPERATOR_MAPPING).find((key) => XLSX_DV_DECIMAL_OPERATOR_MAPPING[key] === operator);
|
|
24643
|
+
}
|
|
24644
|
+
/**
|
|
24645
|
+
* Convert the o-spreadsheet data validation date
|
|
24646
|
+
* criterion type to the corresponding excel operator.
|
|
24647
|
+
*/
|
|
24648
|
+
function convertDateCriterionTypeToExcelOperator(operator) {
|
|
24649
|
+
return Object.keys(XLSX_DV_DATE_OPERATOR_TO_DV_TYPE_MAPPING).find((key) => XLSX_DV_DATE_OPERATOR_TO_DV_TYPE_MAPPING[key] === operator);
|
|
24650
|
+
}
|
|
24599
24651
|
|
|
24600
24652
|
function convertFigures(sheetData) {
|
|
24601
24653
|
let id = 1;
|
|
@@ -24705,6 +24757,112 @@ function getPositionFromAnchor(anchor, sheetData) {
|
|
|
24705
24757
|
};
|
|
24706
24758
|
}
|
|
24707
24759
|
|
|
24760
|
+
function convertDataValidationRules(xlsxDataValidations, warningManager) {
|
|
24761
|
+
const dvRules = [];
|
|
24762
|
+
let dvId = 1;
|
|
24763
|
+
for (const dv of xlsxDataValidations) {
|
|
24764
|
+
if (!dv) {
|
|
24765
|
+
continue;
|
|
24766
|
+
}
|
|
24767
|
+
switch (dv.type) {
|
|
24768
|
+
case "time":
|
|
24769
|
+
warningManager.generateNotSupportedWarning(WarningTypes.TimeDataValidationNotSupported);
|
|
24770
|
+
break;
|
|
24771
|
+
case "textLength":
|
|
24772
|
+
warningManager.generateNotSupportedWarning(WarningTypes.TextLengthDataValidationNotSupported);
|
|
24773
|
+
break;
|
|
24774
|
+
case "whole":
|
|
24775
|
+
warningManager.generateNotSupportedWarning(WarningTypes.WholeNumberDataValidationNotSupported);
|
|
24776
|
+
break;
|
|
24777
|
+
case "decimal":
|
|
24778
|
+
const decimalRule = convertDecimalRule(dvId++, dv);
|
|
24779
|
+
dvRules.push(decimalRule);
|
|
24780
|
+
break;
|
|
24781
|
+
case "list":
|
|
24782
|
+
const listRule = convertListrule(dvId++, dv);
|
|
24783
|
+
dvRules.push(listRule);
|
|
24784
|
+
break;
|
|
24785
|
+
case "date":
|
|
24786
|
+
if (dv.operator === "notEqual") {
|
|
24787
|
+
warningManager.generateNotSupportedWarning(WarningTypes.NotEqualDateDataValidationNotSupported);
|
|
24788
|
+
break;
|
|
24789
|
+
}
|
|
24790
|
+
const dateRule = convertDateRule(dvId++, dv);
|
|
24791
|
+
dvRules.push(dateRule);
|
|
24792
|
+
break;
|
|
24793
|
+
case "custom":
|
|
24794
|
+
const customRule = convertCustomRule(dvId++, dv);
|
|
24795
|
+
dvRules.push(customRule);
|
|
24796
|
+
break;
|
|
24797
|
+
}
|
|
24798
|
+
}
|
|
24799
|
+
return dvRules;
|
|
24800
|
+
}
|
|
24801
|
+
function convertDecimalRule(id, dv) {
|
|
24802
|
+
const values = [dv.formula1.toString()];
|
|
24803
|
+
if (dv.formula2) {
|
|
24804
|
+
values.push(dv.formula2.toString());
|
|
24805
|
+
}
|
|
24806
|
+
return {
|
|
24807
|
+
id: id.toString(),
|
|
24808
|
+
ranges: dv.sqref,
|
|
24809
|
+
isBlocking: dv.errorStyle !== "warning",
|
|
24810
|
+
criterion: {
|
|
24811
|
+
type: XLSX_DV_DECIMAL_OPERATOR_MAPPING[dv.operator],
|
|
24812
|
+
values,
|
|
24813
|
+
},
|
|
24814
|
+
};
|
|
24815
|
+
}
|
|
24816
|
+
function convertListrule(id, dv) {
|
|
24817
|
+
const formula1 = dv.formula1.toString();
|
|
24818
|
+
const isRangeRule = rangeReference.test(formula1);
|
|
24819
|
+
return {
|
|
24820
|
+
id: id.toString(),
|
|
24821
|
+
ranges: dv.sqref,
|
|
24822
|
+
isBlocking: dv.errorStyle !== "warning",
|
|
24823
|
+
criterion: {
|
|
24824
|
+
type: isRangeRule ? "isValueInRange" : "isValueInList",
|
|
24825
|
+
values: isRangeRule ? [formula1] : formula1.replaceAll('"', "").split(","),
|
|
24826
|
+
displayStyle: "arrow",
|
|
24827
|
+
},
|
|
24828
|
+
};
|
|
24829
|
+
}
|
|
24830
|
+
function convertDateRule(id, dv) {
|
|
24831
|
+
let criterion;
|
|
24832
|
+
const values = [dv.formula1.toString()];
|
|
24833
|
+
if (dv.formula2) {
|
|
24834
|
+
values.push(dv.formula2.toString());
|
|
24835
|
+
criterion = {
|
|
24836
|
+
type: XLSX_DV_DATE_OPERATOR_TO_DV_TYPE_MAPPING[dv.operator],
|
|
24837
|
+
values: getDateCriterionFormattedValues(values, DEFAULT_LOCALE),
|
|
24838
|
+
};
|
|
24839
|
+
}
|
|
24840
|
+
else {
|
|
24841
|
+
criterion = {
|
|
24842
|
+
type: XLSX_DV_DATE_OPERATOR_TO_DV_TYPE_MAPPING[dv.operator],
|
|
24843
|
+
values: getDateCriterionFormattedValues(values, DEFAULT_LOCALE),
|
|
24844
|
+
dateValue: "exactDate",
|
|
24845
|
+
};
|
|
24846
|
+
}
|
|
24847
|
+
return {
|
|
24848
|
+
id: id.toString(),
|
|
24849
|
+
ranges: dv.sqref,
|
|
24850
|
+
isBlocking: dv.errorStyle !== "warning",
|
|
24851
|
+
criterion: criterion,
|
|
24852
|
+
};
|
|
24853
|
+
}
|
|
24854
|
+
function convertCustomRule(id, dv) {
|
|
24855
|
+
return {
|
|
24856
|
+
id: id.toString(),
|
|
24857
|
+
ranges: dv.sqref,
|
|
24858
|
+
isBlocking: dv.errorStyle !== "warning",
|
|
24859
|
+
criterion: {
|
|
24860
|
+
type: "customFormula",
|
|
24861
|
+
values: [`=${dv.formula1.toString()}`],
|
|
24862
|
+
},
|
|
24863
|
+
};
|
|
24864
|
+
}
|
|
24865
|
+
|
|
24708
24866
|
/**
|
|
24709
24867
|
* Match external reference (ex. '[1]Sheet 3'!$B$4)
|
|
24710
24868
|
*
|
|
@@ -24825,6 +24983,7 @@ function convertSheets(data, warningManager) {
|
|
|
24825
24983
|
cols: convertCols(sheet, sheetDims[0], colHeaderGroups),
|
|
24826
24984
|
rows: convertRows(sheet, sheetDims[1], rowHeaderGroups),
|
|
24827
24985
|
conditionalFormats: convertConditionalFormats(sheet.cfs, data.dxfs, warningManager),
|
|
24986
|
+
dataValidationRules: convertDataValidationRules(sheet.dataValidations, warningManager),
|
|
24828
24987
|
figures: convertFigures(sheet),
|
|
24829
24988
|
isVisible: sheet.isVisible,
|
|
24830
24989
|
panes: sheetOptions
|
|
@@ -26105,6 +26264,41 @@ class XlsxCfExtractor extends XlsxBaseExtractor {
|
|
|
26105
26264
|
}
|
|
26106
26265
|
}
|
|
26107
26266
|
|
|
26267
|
+
class XlsxDataValidationExtractor extends XlsxBaseExtractor {
|
|
26268
|
+
theme;
|
|
26269
|
+
constructor(sheetFile, xlsxStructure, warningManager, theme) {
|
|
26270
|
+
super(sheetFile, xlsxStructure, warningManager);
|
|
26271
|
+
this.theme = theme;
|
|
26272
|
+
}
|
|
26273
|
+
extractDataValidations() {
|
|
26274
|
+
const dataValidations = this.mapOnElements({ parent: this.rootFile.file.xml, query: "worksheet > dataValidations > dataValidation" }, (dvElement) => {
|
|
26275
|
+
return {
|
|
26276
|
+
type: this.extractAttr(dvElement, "type", { required: true }).asString(),
|
|
26277
|
+
operator: this.extractAttr(dvElement, "operator", {
|
|
26278
|
+
default: "between",
|
|
26279
|
+
})?.asString(),
|
|
26280
|
+
sqref: this.extractAttr(dvElement, "sqref", { required: true }).asString().split(" "),
|
|
26281
|
+
errorStyle: this.extractAttr(dvElement, "errorStyle")?.asString(),
|
|
26282
|
+
formula1: this.extractDataValidationFormula(dvElement, 1)[0],
|
|
26283
|
+
formula2: this.extractDataValidationFormula(dvElement, 2)[0],
|
|
26284
|
+
showErrorMessage: this.extractAttr(dvElement, "showErrorMessage")?.asBool(),
|
|
26285
|
+
errorTitle: this.extractAttr(dvElement, "errorTitle")?.asString(),
|
|
26286
|
+
error: this.extractAttr(dvElement, "error")?.asString(),
|
|
26287
|
+
showInputMessage: this.extractAttr(dvElement, "showInputMessage")?.asBool(),
|
|
26288
|
+
promptTitle: this.extractAttr(dvElement, "promptTitle")?.asString(),
|
|
26289
|
+
prompt: this.extractAttr(dvElement, "prompt")?.asString(),
|
|
26290
|
+
allowBlank: this.extractAttr(dvElement, "allowBlank")?.asBool(),
|
|
26291
|
+
};
|
|
26292
|
+
});
|
|
26293
|
+
return dataValidations;
|
|
26294
|
+
}
|
|
26295
|
+
extractDataValidationFormula(dvElement, index) {
|
|
26296
|
+
return this.mapOnElements({ parent: dvElement, query: `formula${index}` }, (cfFormulaElements) => {
|
|
26297
|
+
return this.extractTextContent(cfFormulaElements, { required: true });
|
|
26298
|
+
});
|
|
26299
|
+
}
|
|
26300
|
+
}
|
|
26301
|
+
|
|
26108
26302
|
class XlsxChartExtractor extends XlsxBaseExtractor {
|
|
26109
26303
|
extractChart() {
|
|
26110
26304
|
return this.mapOnElements({ parent: this.rootFile.file.xml, query: "c:chartSpace" }, (rootChartElement) => {
|
|
@@ -26472,6 +26666,7 @@ class XlsxSheetExtractor extends XlsxBaseExtractor {
|
|
|
26472
26666
|
sharedFormulas: this.extractSharedFormulas(sheetElement),
|
|
26473
26667
|
merges: this.extractMerges(sheetElement),
|
|
26474
26668
|
cfs: this.extractConditionalFormats(),
|
|
26669
|
+
dataValidations: this.extractDataValidations(),
|
|
26475
26670
|
figures: this.extractFigures(sheetElement),
|
|
26476
26671
|
hyperlinks: this.extractHyperLinks(sheetElement),
|
|
26477
26672
|
tables: this.extractTables(sheetElement),
|
|
@@ -26543,6 +26738,9 @@ class XlsxSheetExtractor extends XlsxBaseExtractor {
|
|
|
26543
26738
|
extractConditionalFormats() {
|
|
26544
26739
|
return new XlsxCfExtractor(this.rootFile, this.xlsxFileStructure, this.warningManager, this.theme).extractConditionalFormattings();
|
|
26545
26740
|
}
|
|
26741
|
+
extractDataValidations() {
|
|
26742
|
+
return new XlsxDataValidationExtractor(this.rootFile, this.xlsxFileStructure, this.warningManager, this.theme).extractDataValidations();
|
|
26743
|
+
}
|
|
26546
26744
|
extractFigures(worksheet) {
|
|
26547
26745
|
const figures = this.mapOnElements({ parent: worksheet, query: "drawing" }, (drawingElement) => {
|
|
26548
26746
|
const drawingId = this.extractAttr(drawingElement, "r:id", { required: true })?.asString();
|
|
@@ -27823,6 +28021,7 @@ function createEmptySheet(sheetId, name) {
|
|
|
27823
28021
|
rows: {},
|
|
27824
28022
|
merges: [],
|
|
27825
28023
|
conditionalFormats: [],
|
|
28024
|
+
dataValidationRules: [],
|
|
27826
28025
|
figures: [],
|
|
27827
28026
|
tables: [],
|
|
27828
28027
|
isVisible: true,
|
|
@@ -31386,6 +31585,10 @@ class Popover extends Component {
|
|
|
31386
31585
|
this.currentDisplayValue = newDisplay;
|
|
31387
31586
|
if (!anchor)
|
|
31388
31587
|
return;
|
|
31588
|
+
el.style.top = "";
|
|
31589
|
+
el.style.left = "";
|
|
31590
|
+
el.style["max-height"] = "";
|
|
31591
|
+
el.style["max-width"] = "";
|
|
31389
31592
|
const propsMaxSize = { width: this.props.maxWidth, height: this.props.maxHeight };
|
|
31390
31593
|
let elDims = {
|
|
31391
31594
|
width: el.getBoundingClientRect().width,
|
|
@@ -40246,7 +40449,7 @@ dataValidationEvaluatorRegistry.add("dateIs", {
|
|
|
40246
40449
|
name: _t("Date is"),
|
|
40247
40450
|
getPreview: (criterion, getters) => {
|
|
40248
40451
|
return criterion.dateValue === "exactDate"
|
|
40249
|
-
? _t("Date is %s", getDateCriterionFormattedValues(criterion, getters)[0])
|
|
40452
|
+
? _t("Date is %s", getDateCriterionFormattedValues(criterion.values, getters.getLocale())[0])
|
|
40250
40453
|
: _t("Date is %s", DVTerms.DateIs[criterion.dateValue]);
|
|
40251
40454
|
},
|
|
40252
40455
|
});
|
|
@@ -40271,7 +40474,7 @@ dataValidationEvaluatorRegistry.add("dateIsBefore", {
|
|
|
40271
40474
|
name: _t("Date is before"),
|
|
40272
40475
|
getPreview: (criterion, getters) => {
|
|
40273
40476
|
return criterion.dateValue === "exactDate"
|
|
40274
|
-
? _t("Date is before %s", getDateCriterionFormattedValues(criterion, getters)[0])
|
|
40477
|
+
? _t("Date is before %s", getDateCriterionFormattedValues(criterion.values, getters.getLocale())[0])
|
|
40275
40478
|
: _t("Date is before %s", DVTerms.DateIsBefore[criterion.dateValue]);
|
|
40276
40479
|
},
|
|
40277
40480
|
});
|
|
@@ -40296,7 +40499,7 @@ dataValidationEvaluatorRegistry.add("dateIsOnOrBefore", {
|
|
|
40296
40499
|
name: _t("Date is on or before"),
|
|
40297
40500
|
getPreview: (criterion, getters) => {
|
|
40298
40501
|
return criterion.dateValue === "exactDate"
|
|
40299
|
-
? _t("Date is on or before %s", getDateCriterionFormattedValues(criterion, getters)[0])
|
|
40502
|
+
? _t("Date is on or before %s", getDateCriterionFormattedValues(criterion.values, getters.getLocale())[0])
|
|
40300
40503
|
: _t("Date is on or before %s", DVTerms.DateIsBefore[criterion.dateValue]);
|
|
40301
40504
|
},
|
|
40302
40505
|
});
|
|
@@ -40321,7 +40524,7 @@ dataValidationEvaluatorRegistry.add("dateIsAfter", {
|
|
|
40321
40524
|
name: _t("Date is after"),
|
|
40322
40525
|
getPreview: (criterion, getters) => {
|
|
40323
40526
|
return criterion.dateValue === "exactDate"
|
|
40324
|
-
? _t("Date is after %s", getDateCriterionFormattedValues(criterion, getters)[0])
|
|
40527
|
+
? _t("Date is after %s", getDateCriterionFormattedValues(criterion.values, getters.getLocale())[0])
|
|
40325
40528
|
: _t("Date is after %s", DVTerms.DateIsBefore[criterion.dateValue]);
|
|
40326
40529
|
},
|
|
40327
40530
|
});
|
|
@@ -40346,7 +40549,7 @@ dataValidationEvaluatorRegistry.add("dateIsOnOrAfter", {
|
|
|
40346
40549
|
name: _t("Date is on or after"),
|
|
40347
40550
|
getPreview: (criterion, getters) => {
|
|
40348
40551
|
return criterion.dateValue === "exactDate"
|
|
40349
|
-
? _t("Date is on or after %s", getDateCriterionFormattedValues(criterion, getters)[0])
|
|
40552
|
+
? _t("Date is on or after %s", getDateCriterionFormattedValues(criterion.values, getters.getLocale())[0])
|
|
40350
40553
|
: _t("Date is on or after %s", DVTerms.DateIsBefore[criterion.dateValue]);
|
|
40351
40554
|
},
|
|
40352
40555
|
});
|
|
@@ -40372,7 +40575,7 @@ dataValidationEvaluatorRegistry.add("dateIsBetween", {
|
|
|
40372
40575
|
numberOfValues: () => 2,
|
|
40373
40576
|
name: _t("Date is between"),
|
|
40374
40577
|
getPreview: (criterion, getters) => {
|
|
40375
|
-
const values = getDateCriterionFormattedValues(criterion, getters);
|
|
40578
|
+
const values = getDateCriterionFormattedValues(criterion.values, getters.getLocale());
|
|
40376
40579
|
return _t("Date is between %s and %s", values[0], values[1]);
|
|
40377
40580
|
},
|
|
40378
40581
|
});
|
|
@@ -40398,7 +40601,7 @@ dataValidationEvaluatorRegistry.add("dateIsNotBetween", {
|
|
|
40398
40601
|
numberOfValues: () => 2,
|
|
40399
40602
|
name: _t("Date is not between"),
|
|
40400
40603
|
getPreview: (criterion, getters) => {
|
|
40401
|
-
const values = getDateCriterionFormattedValues(criterion, getters);
|
|
40604
|
+
const values = getDateCriterionFormattedValues(criterion.values, getters.getLocale());
|
|
40402
40605
|
return _t("Date is not between %s and %s", values[0], values[1]);
|
|
40403
40606
|
},
|
|
40404
40607
|
});
|
|
@@ -40681,19 +40884,6 @@ function checkValueIsNumber(value) {
|
|
|
40681
40884
|
const valueAsNumber = tryToNumber(value, DEFAULT_LOCALE);
|
|
40682
40885
|
return valueAsNumber !== undefined;
|
|
40683
40886
|
}
|
|
40684
|
-
function getDateCriterionFormattedValues(criterion, getters) {
|
|
40685
|
-
const locale = getters.getLocale();
|
|
40686
|
-
return criterion.values.map((valueStr) => {
|
|
40687
|
-
if (valueStr.startsWith("=")) {
|
|
40688
|
-
return valueStr;
|
|
40689
|
-
}
|
|
40690
|
-
const value = parseLiteral(valueStr, locale);
|
|
40691
|
-
if (typeof value === "number") {
|
|
40692
|
-
return formatValue(value, { format: locale.dateFormat, locale });
|
|
40693
|
-
}
|
|
40694
|
-
return "";
|
|
40695
|
-
});
|
|
40696
|
-
}
|
|
40697
40887
|
|
|
40698
40888
|
/** This component looks like a select input, but on click it opens a Menu with the items given as props instead of a dropdown */
|
|
40699
40889
|
class SelectMenu extends Component {
|
|
@@ -46396,7 +46586,7 @@ class GridComposer extends Component {
|
|
|
46396
46586
|
return;
|
|
46397
46587
|
}
|
|
46398
46588
|
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
46399
|
-
const zone = this.env.model.getters.
|
|
46589
|
+
const zone = positionToZone(this.env.model.getters.getSelection().anchor.cell);
|
|
46400
46590
|
const rect = this.env.model.getters.getVisibleRect(zone);
|
|
46401
46591
|
if (!deepEquals(rect, this.rect) || sheetId !== this.composerStore.currentEditedCell.sheetId) {
|
|
46402
46592
|
this.isCellReferenceVisible = true;
|
|
@@ -48230,13 +48420,23 @@ class GridRenderer {
|
|
|
48230
48420
|
drawLayer(renderingContext, layer) {
|
|
48231
48421
|
switch (layer) {
|
|
48232
48422
|
case "Background":
|
|
48233
|
-
|
|
48234
|
-
this.
|
|
48235
|
-
|
|
48236
|
-
|
|
48237
|
-
|
|
48238
|
-
|
|
48239
|
-
|
|
48423
|
+
this.drawGlobalBackground(renderingContext);
|
|
48424
|
+
for (const zone of this.getters.getAllActiveViewportsZones()) {
|
|
48425
|
+
const { ctx } = renderingContext;
|
|
48426
|
+
ctx.save();
|
|
48427
|
+
ctx.beginPath();
|
|
48428
|
+
const rect = this.getters.getVisibleRect(zone);
|
|
48429
|
+
ctx.rect(rect.x, rect.y, rect.width, rect.height);
|
|
48430
|
+
ctx.clip();
|
|
48431
|
+
const boxes = this.getGridBoxes(zone);
|
|
48432
|
+
this.drawBackground(renderingContext, boxes);
|
|
48433
|
+
this.drawOverflowingCellBackground(renderingContext, boxes);
|
|
48434
|
+
this.drawCellBackground(renderingContext, boxes);
|
|
48435
|
+
this.drawBorders(renderingContext, boxes);
|
|
48436
|
+
this.drawTexts(renderingContext, boxes);
|
|
48437
|
+
this.drawIcon(renderingContext, boxes);
|
|
48438
|
+
ctx.restore();
|
|
48439
|
+
}
|
|
48240
48440
|
this.drawFrozenPanes(renderingContext);
|
|
48241
48441
|
break;
|
|
48242
48442
|
case "Headers":
|
|
@@ -48247,12 +48447,15 @@ class GridRenderer {
|
|
|
48247
48447
|
break;
|
|
48248
48448
|
}
|
|
48249
48449
|
}
|
|
48250
|
-
|
|
48251
|
-
const { ctx
|
|
48450
|
+
drawGlobalBackground(renderingContext) {
|
|
48451
|
+
const { ctx } = renderingContext;
|
|
48252
48452
|
const { width, height } = this.getters.getSheetViewDimensionWithHeaders();
|
|
48253
48453
|
// white background
|
|
48254
48454
|
ctx.fillStyle = "#ffffff";
|
|
48255
48455
|
ctx.fillRect(0, 0, width + CANVAS_SHIFT, height + CANVAS_SHIFT);
|
|
48456
|
+
}
|
|
48457
|
+
drawBackground(renderingContext, boxes) {
|
|
48458
|
+
const { ctx, thinLineWidth } = renderingContext;
|
|
48256
48459
|
const areGridLinesVisible = !this.getters.isDashboard() &&
|
|
48257
48460
|
this.getters.getGridLinesVisibility(this.getters.getActiveSheetId());
|
|
48258
48461
|
const inset = areGridLinesVisible ? 0.1 * thinLineWidth : 0;
|
|
@@ -48683,7 +48886,7 @@ class GridRenderer {
|
|
|
48683
48886
|
const position = { sheetId, col, row };
|
|
48684
48887
|
const cell = this.getters.getEvaluatedCell(position);
|
|
48685
48888
|
const showFormula = this.getters.shouldShowFormulas();
|
|
48686
|
-
const { x, y, width, height } = this.getters.
|
|
48889
|
+
const { x, y, width, height } = this.getters.getRect(zone);
|
|
48687
48890
|
const { verticalAlign } = this.getters.getCellStyle(position);
|
|
48688
48891
|
const box = {
|
|
48689
48892
|
x,
|
|
@@ -48801,12 +49004,16 @@ class GridRenderer {
|
|
|
48801
49004
|
}
|
|
48802
49005
|
return box;
|
|
48803
49006
|
}
|
|
48804
|
-
getGridBoxes() {
|
|
49007
|
+
getGridBoxes(zone) {
|
|
48805
49008
|
const boxes = [];
|
|
48806
|
-
const visibleCols = this.getters
|
|
49009
|
+
const visibleCols = this.getters
|
|
49010
|
+
.getSheetViewVisibleCols()
|
|
49011
|
+
.filter((col) => col >= zone.left && col <= zone.right);
|
|
48807
49012
|
const left = visibleCols[0];
|
|
48808
49013
|
const right = visibleCols[visibleCols.length - 1];
|
|
48809
|
-
const visibleRows = this.getters
|
|
49014
|
+
const visibleRows = this.getters
|
|
49015
|
+
.getSheetViewVisibleRows()
|
|
49016
|
+
.filter((row) => row >= zone.top && row <= zone.bottom);
|
|
48810
49017
|
const top = visibleRows[0];
|
|
48811
49018
|
const bottom = visibleRows[visibleRows.length - 1];
|
|
48812
49019
|
const viewport = { left, right, top, bottom };
|
|
@@ -52290,6 +52497,20 @@ class DataValidationPlugin extends CorePlugin {
|
|
|
52290
52497
|
}
|
|
52291
52498
|
}
|
|
52292
52499
|
}
|
|
52500
|
+
exportForExcel(data) {
|
|
52501
|
+
if (!data.sheets) {
|
|
52502
|
+
return;
|
|
52503
|
+
}
|
|
52504
|
+
for (const sheet of data.sheets) {
|
|
52505
|
+
sheet.dataValidationRules = [];
|
|
52506
|
+
for (const rule of this.rules[sheet.id]) {
|
|
52507
|
+
sheet.dataValidationRules.push({
|
|
52508
|
+
...rule,
|
|
52509
|
+
ranges: rule.ranges.map((range) => this.getters.getRangeString(range, sheet.id, { useFixedReference: true })),
|
|
52510
|
+
});
|
|
52511
|
+
}
|
|
52512
|
+
}
|
|
52513
|
+
}
|
|
52293
52514
|
checkCriterionTypeIsValid(cmd) {
|
|
52294
52515
|
return dataValidationEvaluatorRegistry.contains(cmd.rule.criterion.type)
|
|
52295
52516
|
? "Success" /* CommandResult.Success */
|
|
@@ -54057,6 +54278,7 @@ class SheetPlugin extends CorePlugin {
|
|
|
54057
54278
|
formats: {},
|
|
54058
54279
|
borders: {},
|
|
54059
54280
|
conditionalFormats: [],
|
|
54281
|
+
dataValidationRules: [],
|
|
54060
54282
|
figures: [],
|
|
54061
54283
|
tables: [],
|
|
54062
54284
|
areGridLinesVisible: sheet.areGridLinesVisible === undefined ? true : sheet.areGridLinesVisible,
|
|
@@ -61247,9 +61469,6 @@ class Session extends EventBus {
|
|
|
61247
61469
|
}
|
|
61248
61470
|
}
|
|
61249
61471
|
this.acknowledge(message);
|
|
61250
|
-
if (message.type === "REMOTE_REVISION" && message.clientId === this.clientId) {
|
|
61251
|
-
return;
|
|
61252
|
-
}
|
|
61253
61472
|
this.trigger("collaborative-event-received");
|
|
61254
61473
|
}
|
|
61255
61474
|
onClientMoved(message) {
|
|
@@ -64543,8 +64762,12 @@ class GridSelectionPlugin extends UIPlugin {
|
|
|
64543
64762
|
},
|
|
64544
64763
|
];
|
|
64545
64764
|
handler.paste({ zones: pasteTarget, sheetId }, data, { isCutOperation: true });
|
|
64765
|
+
const selection = pasteTarget[0];
|
|
64766
|
+
const col = selection.left;
|
|
64767
|
+
const row = selection.top;
|
|
64768
|
+
this.setSelectionMixin({ zone: selection, cell: { col, row } }, [selection]);
|
|
64546
64769
|
const toRemove = isBasedBefore ? cmd.elements.map((el) => el + thickness) : cmd.elements;
|
|
64547
|
-
let currentIndex = cmd.base;
|
|
64770
|
+
let currentIndex = isBasedBefore ? cmd.base : cmd.base + 1;
|
|
64548
64771
|
for (const element of toRemove) {
|
|
64549
64772
|
const size = this.getters.getHeaderSize(cmd.sheetId, cmd.dimension, element);
|
|
64550
64773
|
this.dispatch("RESIZE_COLUMNS_ROWS", {
|
|
@@ -64827,22 +65050,33 @@ class InternalViewport {
|
|
|
64827
65050
|
}
|
|
64828
65051
|
/**
|
|
64829
65052
|
*
|
|
64830
|
-
*
|
|
64831
|
-
*
|
|
65053
|
+
* Computes the visible coordinates & dimensions of a given zone inside the viewport
|
|
65054
|
+
*
|
|
64832
65055
|
*/
|
|
64833
|
-
|
|
65056
|
+
getVisibleRect(zone) {
|
|
64834
65057
|
const targetZone = intersection(zone, this);
|
|
64835
65058
|
if (targetZone) {
|
|
64836
65059
|
const x = this.getters.getColRowOffset("COL", this.left, targetZone.left) + this.offsetCorrectionX;
|
|
64837
65060
|
const y = this.getters.getColRowOffset("ROW", this.top, targetZone.top) + this.offsetCorrectionY;
|
|
64838
65061
|
const width = Math.min(this.getters.getColRowOffset("COL", targetZone.left, targetZone.right + 1), this.viewportWidth);
|
|
64839
65062
|
const height = Math.min(this.getters.getColRowOffset("ROW", targetZone.top, targetZone.bottom + 1), this.viewportHeight);
|
|
64840
|
-
return {
|
|
64841
|
-
|
|
64842
|
-
|
|
64843
|
-
|
|
64844
|
-
|
|
64845
|
-
|
|
65063
|
+
return { x, y, width, height };
|
|
65064
|
+
}
|
|
65065
|
+
return undefined;
|
|
65066
|
+
}
|
|
65067
|
+
/**
|
|
65068
|
+
*
|
|
65069
|
+
* @returns Computes the absolute coordinates & dimensions of a given zone inside the viewport
|
|
65070
|
+
*
|
|
65071
|
+
*/
|
|
65072
|
+
getFullRect(zone) {
|
|
65073
|
+
const targetZone = intersection(zone, this);
|
|
65074
|
+
if (targetZone) {
|
|
65075
|
+
const x = this.getters.getColRowOffset("COL", this.left, zone.left) + this.offsetCorrectionX;
|
|
65076
|
+
const y = this.getters.getColRowOffset("ROW", this.top, zone.top) + this.offsetCorrectionY;
|
|
65077
|
+
const width = this.getters.getColRowOffset("COL", zone.left, zone.right + 1);
|
|
65078
|
+
const height = this.getters.getColRowOffset("ROW", zone.top, zone.bottom + 1);
|
|
65079
|
+
return { x, y, width, height };
|
|
64846
65080
|
}
|
|
64847
65081
|
return undefined;
|
|
64848
65082
|
}
|
|
@@ -65012,6 +65246,8 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
65012
65246
|
"isPositionVisible",
|
|
65013
65247
|
"getColDimensionsInViewport",
|
|
65014
65248
|
"getRowDimensionsInViewport",
|
|
65249
|
+
"getAllActiveViewportsZones",
|
|
65250
|
+
"getRect",
|
|
65015
65251
|
];
|
|
65016
65252
|
viewports = {};
|
|
65017
65253
|
/**
|
|
@@ -65398,16 +65634,27 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
65398
65634
|
getVisibleRectWithoutHeaders(zone) {
|
|
65399
65635
|
const sheetId = this.getters.getActiveSheetId();
|
|
65400
65636
|
const viewportRects = this.getSubViewports(sheetId)
|
|
65401
|
-
.map((viewport) => viewport.
|
|
65637
|
+
.map((viewport) => viewport.getVisibleRect(zone))
|
|
65402
65638
|
.filter(isDefined);
|
|
65403
65639
|
if (viewportRects.length === 0) {
|
|
65404
65640
|
return { x: 0, y: 0, width: 0, height: 0 };
|
|
65405
65641
|
}
|
|
65406
|
-
|
|
65407
|
-
|
|
65408
|
-
|
|
65409
|
-
|
|
65410
|
-
|
|
65642
|
+
return this.recomposeRect(viewportRects);
|
|
65643
|
+
}
|
|
65644
|
+
/**
|
|
65645
|
+
* Computes the actual size and position (:Rect) of the zone on the canvas
|
|
65646
|
+
* regardless of the viewport dimensions.
|
|
65647
|
+
*/
|
|
65648
|
+
getRect(zone) {
|
|
65649
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
65650
|
+
const viewportRects = this.getSubViewports(sheetId)
|
|
65651
|
+
.map((viewport) => viewport.getFullRect(zone))
|
|
65652
|
+
.filter(isDefined);
|
|
65653
|
+
if (viewportRects.length === 0) {
|
|
65654
|
+
return { x: 0, y: 0, width: 0, height: 0 };
|
|
65655
|
+
}
|
|
65656
|
+
const rect = this.recomposeRect(viewportRects);
|
|
65657
|
+
return { ...rect, x: rect.x + this.gridOffsetX, y: rect.y + this.gridOffsetY };
|
|
65411
65658
|
}
|
|
65412
65659
|
/**
|
|
65413
65660
|
* Returns the position of the MainViewport relatively to the start of the grid (without headers)
|
|
@@ -65451,6 +65698,10 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
65451
65698
|
end: start + (isRowHidden ? 0 : size),
|
|
65452
65699
|
};
|
|
65453
65700
|
}
|
|
65701
|
+
getAllActiveViewportsZones() {
|
|
65702
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
65703
|
+
return this.getSubViewports(sheetId);
|
|
65704
|
+
}
|
|
65454
65705
|
// ---------------------------------------------------------------------------
|
|
65455
65706
|
// Private
|
|
65456
65707
|
// ---------------------------------------------------------------------------
|
|
@@ -65641,6 +65892,13 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
65641
65892
|
const height = this.sheetViewHeight + this.gridOffsetY;
|
|
65642
65893
|
return { xRatio: offsetCorrectionX / width, yRatio: offsetCorrectionY / height };
|
|
65643
65894
|
}
|
|
65895
|
+
recomposeRect(viewportRects) {
|
|
65896
|
+
const x = Math.min(...viewportRects.map((rect) => rect.x));
|
|
65897
|
+
const y = Math.min(...viewportRects.map((rect) => rect.y));
|
|
65898
|
+
const width = Math.max(...viewportRects.map((rect) => rect.x + rect.width)) - x;
|
|
65899
|
+
const height = Math.max(...viewportRects.map((rect) => rect.y + rect.height)) - y;
|
|
65900
|
+
return { x, y, width, height };
|
|
65901
|
+
}
|
|
65644
65902
|
}
|
|
65645
65903
|
|
|
65646
65904
|
class HeaderPositionsUIPlugin extends UIPlugin {
|
|
@@ -70946,6 +71204,124 @@ function getExcelThresholdType(type, position) {
|
|
|
70946
71204
|
}
|
|
70947
71205
|
}
|
|
70948
71206
|
|
|
71207
|
+
function addDataValidationRules(dataValidationRules) {
|
|
71208
|
+
const dvRulesCount = dataValidationRules.length;
|
|
71209
|
+
if (dvRulesCount === 0) {
|
|
71210
|
+
return [];
|
|
71211
|
+
}
|
|
71212
|
+
const dvNodes = [new XMLString(`<dataValidations count="${dvRulesCount}">`)];
|
|
71213
|
+
for (const dvRule of dataValidationRules) {
|
|
71214
|
+
switch (dvRule.criterion.type) {
|
|
71215
|
+
case "dateIs":
|
|
71216
|
+
case "dateIsBefore":
|
|
71217
|
+
case "dateIsOnOrBefore":
|
|
71218
|
+
case "dateIsAfter":
|
|
71219
|
+
case "dateIsOnOrAfter":
|
|
71220
|
+
case "dateIsBetween":
|
|
71221
|
+
case "dateIsNotBetween":
|
|
71222
|
+
dvNodes.push(addDateRule(dvRule));
|
|
71223
|
+
break;
|
|
71224
|
+
case "isEqual":
|
|
71225
|
+
case "isNotEqual":
|
|
71226
|
+
case "isGreaterThan":
|
|
71227
|
+
case "isGreaterOrEqualTo":
|
|
71228
|
+
case "isLessThan":
|
|
71229
|
+
case "isLessOrEqualTo":
|
|
71230
|
+
case "isBetween":
|
|
71231
|
+
case "isNotBetween":
|
|
71232
|
+
dvNodes.push(addDecimalRule(dvRule));
|
|
71233
|
+
break;
|
|
71234
|
+
case "isValueInRange":
|
|
71235
|
+
case "isValueInList":
|
|
71236
|
+
dvNodes.push(addListRule(dvRule));
|
|
71237
|
+
break;
|
|
71238
|
+
case "customFormula":
|
|
71239
|
+
dvNodes.push(addCustomFormulaRule(dvRule));
|
|
71240
|
+
break;
|
|
71241
|
+
default:
|
|
71242
|
+
console.warn(`Data validation ${dvRule.criterion.type} is not supported in xlsx.`);
|
|
71243
|
+
break;
|
|
71244
|
+
}
|
|
71245
|
+
}
|
|
71246
|
+
dvNodes.push(new XMLString("</dataValidations>"));
|
|
71247
|
+
return dvNodes;
|
|
71248
|
+
}
|
|
71249
|
+
function addDateRule(dvRule) {
|
|
71250
|
+
const rule = dvRule.criterion;
|
|
71251
|
+
const formula1 = adaptFormulaToExcel(rule.values[0]);
|
|
71252
|
+
const formula2 = rule.values[1] ? adaptFormulaToExcel(rule.values[1]) : undefined;
|
|
71253
|
+
const operator = convertDateCriterionTypeToExcelOperator(dvRule.criterion.type);
|
|
71254
|
+
const attributes = commonDataValidationAttributes(dvRule);
|
|
71255
|
+
attributes.push(["type", "date"], ["operator", operator]);
|
|
71256
|
+
if (formula2) {
|
|
71257
|
+
return escapeXml /*xml*/ `
|
|
71258
|
+
<dataValidation ${formatAttributes(attributes)}>
|
|
71259
|
+
<formula1>${toNumber(formula1, DEFAULT_LOCALE)}</formula1>
|
|
71260
|
+
<formula2>${toNumber(formula2, DEFAULT_LOCALE)}</formula2>
|
|
71261
|
+
</dataValidation>
|
|
71262
|
+
`;
|
|
71263
|
+
}
|
|
71264
|
+
return escapeXml /*xml*/ `
|
|
71265
|
+
<dataValidation ${formatAttributes(attributes)}>
|
|
71266
|
+
<formula1>${toNumber(formula1, DEFAULT_LOCALE)}</formula1>
|
|
71267
|
+
</dataValidation>
|
|
71268
|
+
`;
|
|
71269
|
+
}
|
|
71270
|
+
function addDecimalRule(dvRule) {
|
|
71271
|
+
const rule = dvRule.criterion;
|
|
71272
|
+
const formula1 = adaptFormulaToExcel(rule.values[0]);
|
|
71273
|
+
const formula2 = rule.values[1] ? adaptFormulaToExcel(rule.values[1]) : undefined;
|
|
71274
|
+
const operator = convertDecimalCriterionTypeToExcelOperator(dvRule.criterion.type);
|
|
71275
|
+
const attributes = commonDataValidationAttributes(dvRule);
|
|
71276
|
+
attributes.push(["type", "decimal"], ["operator", operator]);
|
|
71277
|
+
if (formula2) {
|
|
71278
|
+
return escapeXml /*xml*/ `
|
|
71279
|
+
<dataValidation ${formatAttributes(attributes)}>
|
|
71280
|
+
<formula1>${formula1}</formula1>
|
|
71281
|
+
<formula2>${formula2}</formula2>
|
|
71282
|
+
</dataValidation>
|
|
71283
|
+
`;
|
|
71284
|
+
}
|
|
71285
|
+
return escapeXml /*xml*/ `
|
|
71286
|
+
<dataValidation ${formatAttributes(attributes)}>
|
|
71287
|
+
<formula1>${formula1}</formula1>
|
|
71288
|
+
</dataValidation>
|
|
71289
|
+
`;
|
|
71290
|
+
}
|
|
71291
|
+
function addListRule(dvRule) {
|
|
71292
|
+
const rule = dvRule.criterion;
|
|
71293
|
+
const formula1 = dvRule.criterion.type === "isValueInRange"
|
|
71294
|
+
? adaptFormulaToExcel(rule.values[0])
|
|
71295
|
+
: `"${rule.values.join(",")}"`;
|
|
71296
|
+
const attributes = commonDataValidationAttributes(dvRule);
|
|
71297
|
+
attributes.push(["type", "list"]);
|
|
71298
|
+
return escapeXml /*xml*/ `
|
|
71299
|
+
<dataValidation ${formatAttributes(attributes)}>
|
|
71300
|
+
<formula1>${formula1}</formula1>
|
|
71301
|
+
</dataValidation>
|
|
71302
|
+
`;
|
|
71303
|
+
}
|
|
71304
|
+
function addCustomFormulaRule(dvRule) {
|
|
71305
|
+
const rule = dvRule.criterion;
|
|
71306
|
+
const formula1 = adaptFormulaToExcel(rule.values[0]);
|
|
71307
|
+
const attributes = commonDataValidationAttributes(dvRule);
|
|
71308
|
+
attributes.push(["type", "custom"]);
|
|
71309
|
+
return escapeXml /*xml*/ `
|
|
71310
|
+
<dataValidation ${formatAttributes(attributes)}>
|
|
71311
|
+
<formula1>${formula1}</formula1>
|
|
71312
|
+
</dataValidation>
|
|
71313
|
+
`;
|
|
71314
|
+
}
|
|
71315
|
+
function commonDataValidationAttributes(dvRule) {
|
|
71316
|
+
return [
|
|
71317
|
+
["allowBlank", "1"],
|
|
71318
|
+
["showInputMessage", "1"],
|
|
71319
|
+
["showErrorMessage", "1"],
|
|
71320
|
+
["errorStyle", !dvRule.isBlocking ? "warning" : ""],
|
|
71321
|
+
["sqref", dvRule.ranges.join(" ")],
|
|
71322
|
+
];
|
|
71323
|
+
}
|
|
71324
|
+
|
|
70949
71325
|
function createDrawing(drawingRelIds, sheet, figures) {
|
|
70950
71326
|
const namespaces = [
|
|
70951
71327
|
["xmlns:xdr", NAMESPACE.drawing],
|
|
@@ -71724,6 +72100,7 @@ function createWorksheets(data, construct) {
|
|
|
71724
72100
|
${addRows(construct, data, sheet)}
|
|
71725
72101
|
${addMerges(sheet.merges)}
|
|
71726
72102
|
${joinXmlNodes(addConditionalFormatting(construct.dxfs, sheet.conditionalFormats))}
|
|
72103
|
+
${joinXmlNodes(addDataValidationRules(sheet.dataValidationRules))}
|
|
71727
72104
|
${addHyperlinks(construct, data, sheetIndex)}
|
|
71728
72105
|
${drawingNode}
|
|
71729
72106
|
${tablesNode}
|
|
@@ -72632,6 +73009,6 @@ const constants = {
|
|
|
72632
73009
|
export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
|
|
72633
73010
|
|
|
72634
73011
|
|
|
72635
|
-
__info__.version = "18.0.
|
|
72636
|
-
__info__.date = "2025-01-
|
|
72637
|
-
__info__.hash = "
|
|
73012
|
+
__info__.version = "18.0.11";
|
|
73013
|
+
__info__.date = "2025-01-27T10:08:13.567Z";
|
|
73014
|
+
__info__.hash = "e8c6bd1";
|