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