@shbernal/ts-xlsx 3.1.0 → 3.2.0
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/README.md +30 -23
- package/dist/bytes.d.ts +3 -2
- package/dist/core/address.d.ts +36 -0
- package/dist/core/address.js +47 -9
- package/dist/core/array-formula-ranges.d.ts +33 -0
- package/dist/core/array-formula-ranges.js +62 -0
- package/dist/core/color-resolution.js +2 -2
- package/dist/core/column.js +3 -2
- package/dist/core/comment-thread.d.ts +7 -3
- package/dist/core/conditional-formatting-overlay.d.ts +9 -0
- package/dist/core/conditional-formatting-overlay.js +28 -1
- package/dist/core/conditional-formatting.d.ts +98 -10
- package/dist/core/conditional-formatting.js +42 -1
- package/dist/core/data-validation-overlay.d.ts +5 -0
- package/dist/core/data-validation-overlay.js +15 -0
- package/dist/core/data-validation.d.ts +16 -0
- package/dist/core/data-validation.js +15 -0
- package/dist/core/date-format.js +14 -4
- package/dist/core/date.js +1 -1
- package/dist/core/formula-references.d.ts +26 -0
- package/dist/core/formula-references.js +173 -0
- package/dist/core/formula-scan.d.ts +2 -0
- package/dist/core/formula-scan.js +58 -0
- package/dist/core/formula.d.ts +51 -18
- package/dist/core/formula.js +77 -86
- package/dist/core/function-values.d.ts +4 -0
- package/dist/core/function-values.js +58 -0
- package/dist/core/future-functions.d.ts +3 -0
- package/dist/core/{modern-functions.js → future-functions.js} +119 -88
- package/dist/core/grid-edits.d.ts +28 -0
- package/dist/core/grid-edits.js +193 -25
- package/dist/core/hyperlink.d.ts +39 -0
- package/dist/core/hyperlink.js +88 -0
- package/dist/core/image.d.ts +36 -5
- package/dist/core/image.js +9 -0
- package/dist/core/internal.d.ts +3 -1
- package/dist/core/limits.d.ts +5 -3
- package/dist/core/merge.d.ts +13 -0
- package/dist/core/merge.js +15 -1
- package/dist/core/page-setup.d.ts +26 -11
- package/dist/core/pivot-table.d.ts +49 -10
- package/dist/core/pivot-table.js +55 -21
- package/dist/core/protection.d.ts +66 -4
- package/dist/core/protection.js +4 -0
- package/dist/core/row.js +3 -2
- package/dist/core/structured-reference.d.ts +7 -0
- package/dist/core/structured-reference.js +7 -0
- package/dist/core/table.d.ts +38 -8
- package/dist/core/table.js +37 -7
- package/dist/core/theme.d.ts +2 -0
- package/dist/core/theme.js +4 -1
- package/dist/core/value.d.ts +51 -28
- package/dist/core/value.js +15 -12
- package/dist/core/workbook-styles.d.ts +17 -1
- package/dist/core/workbook-styles.js +4 -0
- package/dist/core/workbook-theme.js +5 -3
- package/dist/core/workbook.d.ts +20 -3
- package/dist/core/workbook.js +26 -5
- package/dist/core/worksheet-merges.d.ts +9 -4
- package/dist/core/worksheet-merges.js +17 -11
- package/dist/core/worksheet-model.d.ts +1 -1
- package/dist/core/worksheet-model.js +4 -0
- package/dist/core/worksheet-pictures.d.ts +3 -3
- package/dist/core/worksheet-pictures.js +7 -6
- package/dist/core/worksheet.d.ts +110 -21
- package/dist/core/worksheet.js +174 -49
- package/dist/entries/core.d.ts +7 -5
- package/dist/entries/core.js +4 -3
- package/dist/entries/errors.d.ts +1 -0
- package/dist/entries/errors.js +1 -0
- package/dist/errors.js +1 -1
- package/dist/io/cell-metadata/metadata.d.ts +42 -0
- package/dist/io/cell-metadata/metadata.js +35 -0
- package/dist/io/cell-metadata/rich-values.d.ts +11 -0
- package/dist/io/cell-metadata/rich-values.js +80 -0
- package/dist/io/csv/delimiter.d.ts +14 -2
- package/dist/io/csv/delimiter.js +12 -0
- package/dist/io/csv/errors.d.ts +14 -0
- package/dist/io/csv/errors.js +5 -0
- package/dist/io/csv/read.d.ts +6 -1
- package/dist/io/csv/read.js +46 -24
- package/dist/io/csv/write.d.ts +10 -3
- package/dist/io/csv/write.js +16 -7
- package/dist/io/opc/part-paths.js +4 -4
- package/dist/io/opc/read-opc.d.ts +4 -0
- package/dist/io/opc/read-opc.js +10 -4
- package/dist/io/opc/strict-relationships.d.ts +2 -0
- package/dist/io/opc/strict-relationships.js +12 -0
- package/dist/io/read-policy/column-budget.d.ts +26 -0
- package/dist/io/{xlsx → read-policy}/column-budget.js +4 -8
- package/dist/io/read-policy/read-repair.d.ts +74 -0
- package/dist/io/read-policy/read-repair.js +119 -0
- package/dist/io/style/cell-style-resolution.d.ts +25 -0
- package/dist/io/style/cell-style-resolution.js +30 -0
- package/dist/io/xlsb/formula.js +4 -2
- package/dist/io/xlsb/ptg-functions.js +110 -0
- package/dist/io/xlsb/read-metadata.d.ts +7 -0
- package/dist/io/xlsb/read-metadata.js +69 -0
- package/dist/io/xlsb/read-worksheet.d.ts +6 -0
- package/dist/io/xlsb/read-worksheet.js +95 -37
- package/dist/io/xlsb/read.js +26 -8
- package/dist/io/xlsb/record-types.d.ts +13 -0
- package/dist/io/xlsb/record-types.js +13 -0
- package/dist/io/xlsb/sheet-protection.d.ts +20 -0
- package/dist/io/xlsb/sheet-protection.js +60 -0
- package/dist/io/xlsx/cell-accumulator.d.ts +20 -12
- package/dist/io/xlsx/cell-accumulator.js +49 -19
- package/dist/io/xlsx/cell-metadata.d.ts +39 -0
- package/dist/io/xlsx/cell-metadata.js +162 -0
- package/dist/io/xlsx/cell-value.d.ts +16 -4
- package/dist/io/xlsx/cell-value.js +38 -21
- package/dist/io/xlsx/color-xml.js +1 -1
- package/dist/io/xlsx/column-span.d.ts +11 -0
- package/dist/io/xlsx/column-span.js +9 -0
- package/dist/io/xlsx/comments.d.ts +3 -28
- package/dist/io/xlsx/comments.js +3 -65
- package/dist/io/xlsx/conditional-formatting.d.ts +42 -25
- package/dist/io/xlsx/conditional-formatting.js +424 -129
- package/dist/io/xlsx/data-validation.d.ts +12 -7
- package/dist/io/xlsx/data-validation.js +41 -29
- package/dist/io/xlsx/edit-vba.js +43 -36
- package/dist/io/xlsx/hyperlinks.d.ts +16 -50
- package/dist/io/xlsx/hyperlinks.js +8 -37
- package/dist/io/xlsx/images.d.ts +49 -16
- package/dist/io/xlsx/images.js +145 -44
- package/dist/io/xlsx/namespaces.d.ts +8 -0
- package/dist/io/xlsx/namespaces.js +4 -0
- package/dist/io/xlsx/package-plan.d.ts +48 -15
- package/dist/io/xlsx/package-plan.js +46 -9
- package/dist/io/xlsx/part-names.d.ts +6 -8
- package/dist/io/xlsx/part-names.js +3 -7
- package/dist/io/xlsx/pivot.d.ts +5 -5
- package/dist/io/xlsx/pivot.js +23 -22
- package/dist/io/xlsx/preserved-splices.d.ts +6 -0
- package/dist/io/xlsx/preserved-splices.js +74 -0
- package/dist/io/xlsx/read-comments.d.ts +29 -0
- package/dist/io/xlsx/read-comments.js +75 -0
- package/dist/io/xlsx/read-parts.d.ts +2 -2
- package/dist/io/xlsx/read-parts.js +44 -37
- package/dist/io/xlsx/read-pivot.js +9 -3
- package/dist/io/xlsx/read-rich-runs.d.ts +8 -5
- package/dist/io/xlsx/read-rich-runs.js +18 -1
- package/dist/io/xlsx/read-rows.d.ts +18 -7
- package/dist/io/xlsx/read-rows.js +47 -37
- package/dist/io/xlsx/read-styles.d.ts +0 -25
- package/dist/io/xlsx/read-styles.js +39 -34
- package/dist/io/xlsx/read-workbook-xml.d.ts +6 -0
- package/dist/io/xlsx/read-workbook-xml.js +9 -4
- package/dist/io/xlsx/read-worksheet.d.ts +8 -3
- package/dist/io/xlsx/read-worksheet.js +45 -23
- package/dist/io/xlsx/read.d.ts +0 -4
- package/dist/io/xlsx/read.js +17 -21
- package/dist/io/xlsx/relationships.d.ts +3 -0
- package/dist/io/xlsx/relationships.js +4 -0
- package/dist/io/xlsx/row-position.d.ts +3 -1
- package/dist/io/xlsx/row-xml.d.ts +18 -7
- package/dist/io/xlsx/row-xml.js +54 -35
- package/dist/io/xlsx/sheet-properties.js +68 -42
- package/dist/io/xlsx/strict-parts.d.ts +7 -0
- package/dist/io/xlsx/strict-parts.js +171 -0
- package/dist/io/xlsx/style-elements.d.ts +0 -2
- package/dist/io/xlsx/style-elements.js +9 -29
- package/dist/io/xlsx/styles.d.ts +5 -0
- package/dist/io/xlsx/styles.js +11 -5
- package/dist/io/xlsx/tables.d.ts +10 -2
- package/dist/io/xlsx/tables.js +49 -42
- package/dist/io/xlsx/theme-xml.d.ts +6 -0
- package/dist/io/xlsx/theme-xml.js +16 -19
- package/dist/io/xlsx/threaded-comments.d.ts +6 -1
- package/dist/io/xlsx/threaded-comments.js +14 -7
- package/dist/io/xlsx/workbook-xml.d.ts +13 -24
- package/dist/io/xlsx/workbook-xml.js +15 -33
- package/dist/io/xlsx/worksheet-xml.d.ts +5 -2
- package/dist/io/xlsx/worksheet-xml.js +37 -69
- package/dist/io/xlsx/write-stream.d.ts +28 -6
- package/dist/io/xlsx/write-stream.js +42 -17
- package/dist/io/xlsx/write.d.ts +11 -4
- package/dist/io/xlsx/write.js +153 -90
- package/dist/rel-type.d.ts +9 -0
- package/dist/rel-type.js +3 -0
- package/dist/vba/bytes.d.ts +2 -0
- package/dist/vba/bytes.js +11 -0
- package/dist/vba/cfb-format.d.ts +47 -0
- package/dist/vba/cfb-format.js +34 -0
- package/dist/vba/cfb-writer.d.ts +1 -2
- package/dist/vba/cfb-writer.js +33 -36
- package/dist/vba/cfb.d.ts +9 -4
- package/dist/vba/cfb.js +55 -43
- package/dist/vba/dir-records.d.ts +6 -0
- package/dist/vba/dir-records.js +10 -2
- package/dist/vba/errors.d.ts +4 -4
- package/dist/vba/index.d.ts +0 -2
- package/dist/vba/index.js +0 -2
- package/dist/vba/ms-ovba.d.ts +6 -2
- package/dist/vba/ms-ovba.js +15 -6
- package/dist/vba/project-editor.js +102 -87
- package/dist/vba/project.d.ts +4 -0
- package/dist/vba/project.js +12 -6
- package/dist/vba/vba-encoding.d.ts +4 -10
- package/dist/vba/vba-encoding.js +2 -15
- package/dist/xml/xml-read.d.ts +29 -1
- package/dist/xml/xml-read.js +56 -0
- package/dist/xml/xml-scan.d.ts +13 -0
- package/dist/xml/xml-scan.js +58 -7
- package/dist/xml/xml.d.ts +33 -1
- package/dist/xml/xml.js +22 -0
- package/package.json +5 -4
- package/skills/ts-xlsx-upstream/SKILL.md +21 -13
- package/dist/core/modern-functions.d.ts +0 -1
- package/dist/io/xlsx/cell-style-resolution.d.ts +0 -25
- package/dist/io/xlsx/cell-style-resolution.js +0 -29
- package/dist/io/xlsx/column-budget.d.ts +0 -26
- package/dist/io/xlsx/read-repair.d.ts +0 -26
- package/dist/io/xlsx/read-repair.js +0 -39
|
@@ -1,102 +1,201 @@
|
|
|
1
|
-
import { isCfValueObjectType, isConditionalFormattingOperator, isConditionalFormattingType, isIconSetType,
|
|
2
|
-
import { stripFormulaEquals } from '../../core/formula.js';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
1
|
+
import { isCfIconSetType, isCfTimePeriod, isCfValueObjectType, isConditionalFormattingOperator, isConditionalFormattingType, isDataBarAxisPosition, isDataBarDirection, isIconSetType, ruleNeedsExtension, } from '../../core/conditional-formatting.js';
|
|
2
|
+
import { mangleFormula, stripFormulaEquals, unmangleFunctions } from '../../core/formula.js';
|
|
3
|
+
import { decodeSqrefRects } from '../../core/merge.js';
|
|
4
|
+
import { InternalError } from '../../errors.js';
|
|
5
|
+
import { coerceNumericLiteral, enumToken, numInteger } from '../../xml/xml-attrs.js';
|
|
6
|
+
import { elementRange, TextCapture, } from '../../xml/xml-read.js';
|
|
7
|
+
import { boolStrict, boolTristate, localName } from '../../xml/xml-scan.js';
|
|
8
|
+
import { boolAttr, checkedToken, escapeAttr, escapeText, intAttr, numberText, textAttr, } from '../../xml/xml.js';
|
|
9
|
+
import { admitting } from '../read-policy/read-repair.js';
|
|
7
10
|
import { colorAttrs, parseColor } from './color-xml.js';
|
|
8
|
-
import { CF_EXT_URI, DATABAR_LINK_EXT_URI, isExtensionElement, XM_NS } from './namespaces.js';
|
|
11
|
+
import { CF_EXT_URI, DATABAR_LINK_EXT_URI, isExtensionElement, isMainNamespaceElement, XM_NS, } from './namespaces.js';
|
|
9
12
|
import { x14Ext } from './x14-ext.js';
|
|
10
13
|
const DEFAULT_DATABAR_CFVO = [{ type: 'min' }, { type: 'max' }];
|
|
11
14
|
const DEFAULT_DATABAR_COLOR = { argb: 'FF638EC6' };
|
|
15
|
+
const CLASSIC_ANCHOR = {
|
|
16
|
+
autoMin: 'min',
|
|
17
|
+
autoMax: 'max',
|
|
18
|
+
};
|
|
12
19
|
function needsDataBarExt(rule) {
|
|
13
20
|
return (rule.gradient !== undefined ||
|
|
21
|
+
rule.border !== undefined ||
|
|
22
|
+
rule.borderColor !== undefined ||
|
|
23
|
+
rule.direction !== undefined ||
|
|
14
24
|
rule.negativeFillColor !== undefined ||
|
|
15
|
-
rule.
|
|
25
|
+
rule.negativeBorderColor !== undefined ||
|
|
26
|
+
rule.negativeBarColorSameAsPositive !== undefined ||
|
|
27
|
+
rule.negativeBarBorderColorSameAsPositive !== undefined ||
|
|
28
|
+
rule.axisPosition !== undefined ||
|
|
29
|
+
rule.axisColor !== undefined ||
|
|
30
|
+
(rule.cfvo ?? []).some((anchor) => CLASSIC_ANCHOR[anchor.type] !== undefined));
|
|
16
31
|
}
|
|
17
|
-
function
|
|
32
|
+
function inExtension(cf, rule) {
|
|
33
|
+
return cf.extended === true || ruleNeedsExtension(rule);
|
|
34
|
+
}
|
|
35
|
+
function extensionGuid(index) {
|
|
18
36
|
return `{00000000-0000-0000-0000-${String(index + 1).padStart(12, '0')}}`;
|
|
19
37
|
}
|
|
20
|
-
export function
|
|
21
|
-
const
|
|
22
|
-
|
|
38
|
+
export function planConditionalFormatting(formattings) {
|
|
39
|
+
const priorities = new Map();
|
|
40
|
+
const extensionIds = new Map();
|
|
41
|
+
let next = 1;
|
|
23
42
|
for (const cf of formattings) {
|
|
24
43
|
for (const rule of cf.rules) {
|
|
25
|
-
|
|
26
|
-
|
|
44
|
+
const priority = rule.priority ?? next;
|
|
45
|
+
intAttr('priority', priority);
|
|
46
|
+
next = Math.max(next, priority) + 1;
|
|
47
|
+
priorities.set(rule, priority);
|
|
48
|
+
if (inExtension(cf, rule) || (rule.type === 'dataBar' && needsDataBarExt(rule))) {
|
|
49
|
+
extensionIds.set(rule, extensionGuid(extensionIds.size));
|
|
50
|
+
}
|
|
27
51
|
}
|
|
28
52
|
}
|
|
29
|
-
return
|
|
53
|
+
return { priorities, extensionIds };
|
|
54
|
+
}
|
|
55
|
+
function priorityOf(plan, rule) {
|
|
56
|
+
const priority = plan.priorities.get(rule);
|
|
57
|
+
if (priority === undefined) {
|
|
58
|
+
throw new InternalError('a conditional format rule reached a serialiser unplanned');
|
|
59
|
+
}
|
|
60
|
+
return priority;
|
|
30
61
|
}
|
|
31
62
|
const SCALE_KINDS = ['dataBar', 'colorScale', 'iconSet'];
|
|
32
63
|
const SCALE_TYPES = new Set(SCALE_KINDS);
|
|
33
|
-
export function conditionalFormattingsXml(formattings, styles,
|
|
34
|
-
|
|
35
|
-
return '';
|
|
36
|
-
const priority = { next: 1 };
|
|
37
|
-
return formattings.map((cf) => blockXml(cf, styles, priority, extLinks)).join('');
|
|
64
|
+
export function conditionalFormattingsXml(formattings, styles, plan, formulaNames) {
|
|
65
|
+
return formattings.map((cf) => blockXml(cf, styles, plan, formulaNames)).join('');
|
|
38
66
|
}
|
|
39
|
-
export function conditionalFormattingsExtXml(formattings,
|
|
67
|
+
export function conditionalFormattingsExtXml(formattings, styles, plan, formulaNames) {
|
|
40
68
|
const items = [];
|
|
41
69
|
for (const cf of formattings) {
|
|
70
|
+
const whole = cf.rules.filter((rule) => inExtension(cf, rule));
|
|
71
|
+
if (whole.length > 0) {
|
|
72
|
+
const rules = whole.map((rule) => extensionRuleXml(rule, styles, plan, formulaNames));
|
|
73
|
+
items.push(extensionBlockXml(cf.ref, rules.join('')));
|
|
74
|
+
}
|
|
42
75
|
for (const rule of cf.rules) {
|
|
43
|
-
const guid =
|
|
44
|
-
if (guid
|
|
45
|
-
|
|
76
|
+
const guid = plan.extensionIds.get(rule);
|
|
77
|
+
if (guid === undefined || inExtension(cf, rule))
|
|
78
|
+
continue;
|
|
79
|
+
items.push(extensionBlockXml(cf.ref, `<x14:cfRule type="dataBar" id="${guid}">${x14DataBarXml(rule, formulaNames, false)}</x14:cfRule>`));
|
|
46
80
|
}
|
|
47
81
|
}
|
|
48
82
|
if (items.length === 0)
|
|
49
83
|
return '';
|
|
50
84
|
return x14Ext(CF_EXT_URI, `<x14:conditionalFormattings>${items.join('')}</x14:conditionalFormattings>`);
|
|
51
85
|
}
|
|
52
|
-
function
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
86
|
+
function extensionBlockXml(ref, rules) {
|
|
87
|
+
return (`<x14:conditionalFormatting xmlns:xm="${XM_NS}">${rules}` +
|
|
88
|
+
`<xm:sqref>${escapeText(ref)}</xm:sqref></x14:conditionalFormatting>`);
|
|
89
|
+
}
|
|
90
|
+
function extensionRuleXml(rule, styles, plan, formulaNames) {
|
|
91
|
+
const attrs = [typeAttr(rule), `priority="${priorityOf(plan, rule)}"`, ...ruleFlagAttrs(rule)];
|
|
92
|
+
const id = plan.extensionIds.get(rule);
|
|
93
|
+
if (id !== undefined)
|
|
94
|
+
attrs.push(`id="${id}"`);
|
|
95
|
+
const body = (SCALE_TYPES.has(rule.type)
|
|
96
|
+
? extensionScaleXml(rule, formulaNames)
|
|
97
|
+
: operandsXml(rule.formulae, 'xm:f', formulaNames)) + inlineDxfXml(rule, styles);
|
|
98
|
+
return body === ''
|
|
99
|
+
? `<x14:cfRule ${attrs.join(' ')}/>`
|
|
100
|
+
: `<x14:cfRule ${attrs.join(' ')}>${body}</x14:cfRule>`;
|
|
101
|
+
}
|
|
102
|
+
function inlineDxfXml(rule, styles) {
|
|
103
|
+
const id = resolveDxfId(rule, styles);
|
|
104
|
+
const fragment = id === undefined ? undefined : styles.differentialStyleFragment(id);
|
|
105
|
+
const range = fragment === undefined ? undefined : elementRange(fragment, ['dxf']);
|
|
106
|
+
if (fragment === undefined || range === undefined)
|
|
107
|
+
return '';
|
|
108
|
+
return `<x14:dxf>${fragment.slice(range.contentStart, range.contentEnd)}</x14:dxf>`;
|
|
109
|
+
}
|
|
110
|
+
function extensionScaleXml(rule, formulaNames) {
|
|
111
|
+
if (rule.type === 'dataBar')
|
|
112
|
+
return x14DataBarXml(rule, formulaNames, true);
|
|
113
|
+
const cfvoXml = cfvoWriter('x14', formulaNames);
|
|
114
|
+
if (rule.type === 'colorScale') {
|
|
115
|
+
const anchors = (rule.cfvo ?? []).map(cfvoXml).join('');
|
|
116
|
+
const colors = (rule.colors ?? []).map((c) => `<x14:color ${colorAttrs(c)}/>`).join('');
|
|
117
|
+
return `<x14:colorScale>${anchors}${colors}</x14:colorScale>`;
|
|
118
|
+
}
|
|
119
|
+
return iconSetXml(rule, cfvoXml, 'x14');
|
|
120
|
+
}
|
|
121
|
+
function x14DataBarXml(rule, formulaNames, whole) {
|
|
122
|
+
const attrs = intAttr('minLength', rule.minLength, 0) +
|
|
123
|
+
intAttr('maxLength', rule.maxLength, 0) +
|
|
124
|
+
(whole && rule.showValue === false ? ' showValue="0"' : '') +
|
|
125
|
+
boolAttr('border', rule.border) +
|
|
126
|
+
boolAttr('gradient', rule.gradient) +
|
|
127
|
+
tokenAttr('direction', rule.direction, isDataBarDirection, 'data bar direction') +
|
|
128
|
+
boolAttr('negativeBarColorSameAsPositive', rule.negativeBarColorSameAsPositive) +
|
|
129
|
+
boolAttr('negativeBarBorderColorSameAsPositive', rule.negativeBarBorderColorSameAsPositive) +
|
|
130
|
+
tokenAttr('axisPosition', rule.axisPosition, isDataBarAxisPosition, 'data bar axis position');
|
|
131
|
+
const children = dataBarAnchors(rule).map(cfvoWriter('x14', formulaNames)).join('') +
|
|
132
|
+
(whole ? x14ColorXml('fillColor', rule.color ?? DEFAULT_DATABAR_COLOR) : '') +
|
|
133
|
+
x14ColorXml('borderColor', rule.borderColor) +
|
|
134
|
+
x14ColorXml('negativeFillColor', rule.negativeFillColor) +
|
|
135
|
+
x14ColorXml('negativeBorderColor', rule.negativeBorderColor) +
|
|
136
|
+
x14ColorXml('axisColor', rule.axisColor);
|
|
137
|
+
return `<x14:dataBar${attrs}>${children}</x14:dataBar>`;
|
|
138
|
+
}
|
|
139
|
+
function x14ColorXml(name, color) {
|
|
140
|
+
return color === undefined ? '' : `<x14:${name} ${colorAttrs(color)}/>`;
|
|
141
|
+
}
|
|
142
|
+
function tokenAttr(name, value, isValid, kind) {
|
|
143
|
+
return value === undefined ? '' : ` ${name}="${checkedToken(value, isValid, kind)}"`;
|
|
63
144
|
}
|
|
64
145
|
function dataBarAnchors(rule) {
|
|
65
146
|
return rule.cfvo && rule.cfvo.length > 0 ? rule.cfvo : DEFAULT_DATABAR_CFVO;
|
|
66
147
|
}
|
|
67
|
-
function cfvoWriter(form) {
|
|
148
|
+
function cfvoWriter(form, formulaNames) {
|
|
68
149
|
return (cfvo) => {
|
|
69
|
-
const
|
|
150
|
+
const checked = checkedToken(cfvo.type, isCfValueObjectType, 'conditional format value type');
|
|
151
|
+
const type = form === 'classic' ? (CLASSIC_ANCHOR[cfvo.type] ?? checked) : checked;
|
|
70
152
|
const tag = form === 'classic' ? 'cfvo' : 'x14:cfvo';
|
|
153
|
+
const gte = cfvo.gte === false ? ' gte="0"' : '';
|
|
71
154
|
if (cfvo.value === undefined)
|
|
72
|
-
return `<${tag} type="${type}"/>`;
|
|
73
|
-
const value =
|
|
155
|
+
return `<${tag} type="${type}"${gte}/>`;
|
|
156
|
+
const value = typeof cfvo.value === 'number'
|
|
157
|
+
? numberText(cfvo.value)
|
|
158
|
+
: type === 'formula'
|
|
159
|
+
? mangleFormula(cfvo.value, formulaNames)
|
|
160
|
+
: cfvo.value;
|
|
74
161
|
return form === 'classic'
|
|
75
|
-
? `<${tag} type="${type}"${textAttr('val', value)}/>`
|
|
76
|
-
: `<${tag} type="${type}"><xm:f>${escapeText(value)}</xm:f></${tag}>`;
|
|
162
|
+
? `<${tag} type="${type}"${textAttr('val', value)}${gte}/>`
|
|
163
|
+
: `<${tag} type="${type}"${gte}><xm:f>${escapeText(value)}</xm:f></${tag}>`;
|
|
77
164
|
};
|
|
78
165
|
}
|
|
79
|
-
const cfvoXml = cfvoWriter('classic');
|
|
80
|
-
const x14Cfvo = cfvoWriter('x14');
|
|
81
166
|
function cfRuleExtLinkXml(guid) {
|
|
82
167
|
return `<extLst>${x14Ext(DATABAR_LINK_EXT_URI, `<x14:id>${guid}</x14:id>`)}</extLst>`;
|
|
83
168
|
}
|
|
84
|
-
function blockXml(cf, styles,
|
|
85
|
-
const rules = cf.rules
|
|
169
|
+
function blockXml(cf, styles, plan, formulaNames) {
|
|
170
|
+
const rules = cf.rules
|
|
171
|
+
.filter((rule) => !inExtension(cf, rule))
|
|
172
|
+
.map((rule) => ruleXml(rule, styles, plan, formulaNames))
|
|
173
|
+
.join('');
|
|
86
174
|
if (rules === '')
|
|
87
175
|
return '';
|
|
88
176
|
return `<conditionalFormatting sqref="${escapeAttr(cf.ref)}">${rules}</conditionalFormatting>`;
|
|
89
177
|
}
|
|
90
|
-
function ruleXml(rule, styles,
|
|
91
|
-
const
|
|
92
|
-
priority.next = Math.max(priority.next, p) + 1;
|
|
93
|
-
const attrs = [
|
|
94
|
-
`type="${checkedToken(rule.type, isConditionalFormattingType, 'conditional formatting type')}"`,
|
|
95
|
-
];
|
|
178
|
+
function ruleXml(rule, styles, plan, formulaNames) {
|
|
179
|
+
const attrs = [typeAttr(rule)];
|
|
96
180
|
const dxfId = resolveDxfId(rule, styles);
|
|
97
181
|
if (dxfId !== undefined)
|
|
98
182
|
attrs.push(`dxfId="${dxfId}"`);
|
|
99
|
-
attrs.push(`priority="${
|
|
183
|
+
attrs.push(`priority="${priorityOf(plan, rule)}"`, ...ruleFlagAttrs(rule));
|
|
184
|
+
const extGuid = plan.extensionIds.get(rule);
|
|
185
|
+
let body = SCALE_TYPES.has(rule.type)
|
|
186
|
+
? scaleXml(rule, formulaNames, extGuid !== undefined)
|
|
187
|
+
: operandsXml(rule.formulae, 'formula', formulaNames);
|
|
188
|
+
if (extGuid !== undefined)
|
|
189
|
+
body += cfRuleExtLinkXml(extGuid);
|
|
190
|
+
return body === ''
|
|
191
|
+
? `<cfRule ${attrs.join(' ')}/>`
|
|
192
|
+
: `<cfRule ${attrs.join(' ')}>${body}</cfRule>`;
|
|
193
|
+
}
|
|
194
|
+
function typeAttr(rule) {
|
|
195
|
+
return `type="${checkedToken(rule.type, isConditionalFormattingType, 'conditional formatting type')}"`;
|
|
196
|
+
}
|
|
197
|
+
function ruleFlagAttrs(rule) {
|
|
198
|
+
const attrs = [];
|
|
100
199
|
if (rule.stopIfTrue)
|
|
101
200
|
attrs.push('stopIfTrue="1"');
|
|
102
201
|
if (rule.aboveAverage === false)
|
|
@@ -116,16 +215,10 @@ function ruleXml(rule, styles, priority, extLinks) {
|
|
|
116
215
|
attrs.push(`timePeriod="${checkedToken(rule.timePeriod, isCfTimePeriod, 'time period')}"`);
|
|
117
216
|
}
|
|
118
217
|
if (rule.rank !== undefined)
|
|
119
|
-
attrs.push(
|
|
218
|
+
attrs.push(intAttr('rank', rule.rank, 0).trim());
|
|
120
219
|
if (rule.stdDev !== undefined)
|
|
121
|
-
attrs.push(
|
|
122
|
-
|
|
123
|
-
const extGuid = extLinks.get(rule);
|
|
124
|
-
if (extGuid !== undefined)
|
|
125
|
-
body += cfRuleExtLinkXml(extGuid);
|
|
126
|
-
return body === ''
|
|
127
|
-
? `<cfRule ${attrs.join(' ')}/>`
|
|
128
|
-
: `<cfRule ${attrs.join(' ')}>${body}</cfRule>`;
|
|
220
|
+
attrs.push(intAttr('stdDev', rule.stdDev).trim());
|
|
221
|
+
return attrs;
|
|
129
222
|
}
|
|
130
223
|
function resolveDxfId(rule, styles) {
|
|
131
224
|
if (SCALE_TYPES.has(rule.type))
|
|
@@ -137,66 +230,221 @@ function resolveDxfId(rule, styles) {
|
|
|
137
230
|
return styles.differentialStyleId(rule.style);
|
|
138
231
|
return undefined;
|
|
139
232
|
}
|
|
140
|
-
function
|
|
233
|
+
function operandsXml(formulae, tag, formulaNames) {
|
|
141
234
|
if (formulae === undefined)
|
|
142
235
|
return '';
|
|
143
|
-
return formulae
|
|
236
|
+
return formulae
|
|
237
|
+
.map((f) => `<${tag}>${escapeText(mangleFormula(stripFormulaEquals(f), formulaNames))}</${tag}>`)
|
|
238
|
+
.join('');
|
|
144
239
|
}
|
|
145
|
-
function scaleXml(rule) {
|
|
240
|
+
function scaleXml(rule, formulaNames, linked) {
|
|
241
|
+
const cfvoXml = cfvoWriter('classic', formulaNames);
|
|
146
242
|
if (rule.type === 'dataBar')
|
|
147
|
-
return dataBarXml(rule);
|
|
243
|
+
return dataBarXml(rule, cfvoXml, linked);
|
|
148
244
|
if (rule.type === 'colorScale')
|
|
149
|
-
return colorScaleXml(rule);
|
|
150
|
-
return iconSetXml(rule);
|
|
245
|
+
return colorScaleXml(rule, cfvoXml);
|
|
246
|
+
return iconSetXml(rule, cfvoXml, 'classic');
|
|
151
247
|
}
|
|
152
|
-
function dataBarXml(rule) {
|
|
248
|
+
function dataBarXml(rule, cfvoXml, linked) {
|
|
153
249
|
const color = rule.color ?? DEFAULT_DATABAR_COLOR;
|
|
154
250
|
const anchors = dataBarAnchors(rule).map(cfvoXml).join('');
|
|
155
|
-
|
|
251
|
+
const lengths = linked
|
|
252
|
+
? ''
|
|
253
|
+
: intAttr('minLength', rule.minLength, 0) + intAttr('maxLength', rule.maxLength, 0);
|
|
254
|
+
const showValue = rule.showValue === false ? ' showValue="0"' : '';
|
|
255
|
+
return `<dataBar${lengths}${showValue}>${anchors}<color ${colorAttrs(color)}/></dataBar>`;
|
|
156
256
|
}
|
|
157
|
-
function colorScaleXml(rule) {
|
|
257
|
+
function colorScaleXml(rule, cfvoXml) {
|
|
158
258
|
const anchors = (rule.cfvo ?? []).map(cfvoXml).join('');
|
|
159
259
|
const colors = (rule.colors ?? []).map((c) => `<color ${colorAttrs(c)}/>`).join('');
|
|
160
260
|
return `<colorScale>${anchors}${colors}</colorScale>`;
|
|
161
261
|
}
|
|
162
|
-
function iconSetXml(rule) {
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
|
|
262
|
+
function iconSetXml(rule, cfvoXml, form) {
|
|
263
|
+
const tag = form === 'classic' ? 'iconSet' : 'x14:iconSet';
|
|
264
|
+
const icons = form === 'x14' ? (rule.icons ?? []) : [];
|
|
265
|
+
const attrs = tokenAttr('iconSet', rule.iconSet, isIconSetType, 'icon set') +
|
|
266
|
+
(rule.showValue === false ? ' showValue="0"' : '') +
|
|
267
|
+
(rule.reverse ? ' reverse="1"' : '') +
|
|
268
|
+
(icons.length > 0 ? ' custom="1"' : '');
|
|
166
269
|
const anchors = (rule.cfvo ?? []).map(cfvoXml).join('');
|
|
167
|
-
return
|
|
270
|
+
return `<${tag}${attrs}>${anchors}${icons.map(cfIconXml).join('')}</${tag}>`;
|
|
271
|
+
}
|
|
272
|
+
function cfIconXml(icon) {
|
|
273
|
+
const iconSet = checkedToken(icon.iconSet, isCfIconSetType, 'custom icon set');
|
|
274
|
+
return `<x14:cfIcon iconSet="${iconSet}"${intAttr('iconId', icon.iconId, 0)}/>`;
|
|
275
|
+
}
|
|
276
|
+
class DxfCapture {
|
|
277
|
+
#xml = '<dxf>';
|
|
278
|
+
#depth = 0;
|
|
279
|
+
#skippingFrom;
|
|
280
|
+
open(name, attrs, selfClosing, scope) {
|
|
281
|
+
const local = localName(name);
|
|
282
|
+
if (this.#skippingFrom === undefined) {
|
|
283
|
+
if (isMainNamespaceElement(scope, name) && local !== 'extLst') {
|
|
284
|
+
const attributes = Object.entries(attrs)
|
|
285
|
+
.filter(([key]) => key !== 'xmlns' && !key.includes(':'))
|
|
286
|
+
.map(([key, value]) => ` ${key}="${escapeAttr(value)}"`)
|
|
287
|
+
.join('');
|
|
288
|
+
this.#xml += `<${local}${attributes}${selfClosing ? '/>' : '>'}`;
|
|
289
|
+
}
|
|
290
|
+
else if (!selfClosing) {
|
|
291
|
+
this.#skippingFrom = this.#depth;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
if (!selfClosing)
|
|
295
|
+
this.#depth += 1;
|
|
296
|
+
}
|
|
297
|
+
close(name) {
|
|
298
|
+
if (this.#depth === 0) {
|
|
299
|
+
this.#xml += '</dxf>';
|
|
300
|
+
return true;
|
|
301
|
+
}
|
|
302
|
+
this.#depth -= 1;
|
|
303
|
+
if (this.#skippingFrom === undefined)
|
|
304
|
+
this.#xml += `</${localName(name)}>`;
|
|
305
|
+
else if (this.#skippingFrom === this.#depth)
|
|
306
|
+
this.#skippingFrom = undefined;
|
|
307
|
+
return false;
|
|
308
|
+
}
|
|
309
|
+
get fragment() {
|
|
310
|
+
return this.#xml;
|
|
311
|
+
}
|
|
168
312
|
}
|
|
169
|
-
export function conditionalFormattingPass() {
|
|
313
|
+
export function conditionalFormattingPass(definedNames, adoptDifferentialStyle) {
|
|
170
314
|
const blocks = [];
|
|
171
315
|
let block;
|
|
172
316
|
let draft;
|
|
173
317
|
let scale;
|
|
174
318
|
const formulaCapture = new TextCapture('formula');
|
|
175
319
|
const linked = [];
|
|
320
|
+
const linkedIds = new Set();
|
|
176
321
|
const extById = new Map();
|
|
177
|
-
let x14Ext;
|
|
178
|
-
let x14ExtId;
|
|
179
322
|
const x14IdCapture = new TextCapture('id');
|
|
323
|
+
let extRules;
|
|
324
|
+
let extRule;
|
|
325
|
+
let extCfvo;
|
|
326
|
+
let extSqref = '';
|
|
327
|
+
const extCapture = new TextCapture(['f', 'sqref']);
|
|
328
|
+
let dxf;
|
|
329
|
+
const closeExtensionRule = () => {
|
|
330
|
+
if (extRule === undefined)
|
|
331
|
+
return;
|
|
332
|
+
const { draft: ruleDraft, id } = extRule;
|
|
333
|
+
extRule = undefined;
|
|
334
|
+
extCfvo = undefined;
|
|
335
|
+
if (id !== undefined && linkedIds.has(id)) {
|
|
336
|
+
extById.set(id, { bar: ruleDraft.bar, cfvo: ruleDraft.cfvo });
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
if (ruleDraft.dxf !== undefined)
|
|
340
|
+
ruleDraft.dxfId = String(adoptDifferentialStyle(ruleDraft.dxf));
|
|
341
|
+
const rule = finalizeRule(ruleDraft);
|
|
342
|
+
if (rule !== undefined)
|
|
343
|
+
extRules?.push(rule);
|
|
344
|
+
};
|
|
345
|
+
const openExtension = (ln, attrs, selfClosing) => {
|
|
346
|
+
if (ln === 'id' && draft !== undefined) {
|
|
347
|
+
x14IdCapture.open(ln, selfClosing);
|
|
348
|
+
}
|
|
349
|
+
else if (ln === 'conditionalFormatting') {
|
|
350
|
+
extRules = [];
|
|
351
|
+
extSqref = '';
|
|
352
|
+
}
|
|
353
|
+
else if (ln === 'cfRule') {
|
|
354
|
+
extRule = { draft: newDraft(attrs), id: attrs.id };
|
|
355
|
+
if (selfClosing)
|
|
356
|
+
closeExtensionRule();
|
|
357
|
+
}
|
|
358
|
+
else if (extRule === undefined) {
|
|
359
|
+
if (extRules !== undefined && ln === 'sqref')
|
|
360
|
+
extCapture.open(ln, selfClosing);
|
|
361
|
+
}
|
|
362
|
+
else {
|
|
363
|
+
readExtensionRuleChild(extRule.draft, ln, attrs, selfClosing);
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
const readExtensionRuleChild = (rule, ln, attrs, selfClosing) => {
|
|
367
|
+
switch (ln) {
|
|
368
|
+
case 'dataBar':
|
|
369
|
+
readDataBarAttrs(rule, attrs);
|
|
370
|
+
break;
|
|
371
|
+
case 'iconSet':
|
|
372
|
+
readIconSetAttrs(rule, attrs);
|
|
373
|
+
break;
|
|
374
|
+
case 'cfvo':
|
|
375
|
+
extCfvo = parseCfvo(attrs, definedNames);
|
|
376
|
+
rule.cfvo.push(extCfvo);
|
|
377
|
+
if (selfClosing)
|
|
378
|
+
extCfvo = undefined;
|
|
379
|
+
break;
|
|
380
|
+
case 'f':
|
|
381
|
+
extCapture.open(ln, selfClosing);
|
|
382
|
+
break;
|
|
383
|
+
case 'color':
|
|
384
|
+
rule.colors.push(parseColor(attrs));
|
|
385
|
+
break;
|
|
386
|
+
case 'fillColor':
|
|
387
|
+
rule.color = parseColor(attrs);
|
|
388
|
+
break;
|
|
389
|
+
case 'borderColor':
|
|
390
|
+
case 'negativeFillColor':
|
|
391
|
+
case 'negativeBorderColor':
|
|
392
|
+
case 'axisColor':
|
|
393
|
+
rule.bar[ln] = parseColor(attrs);
|
|
394
|
+
break;
|
|
395
|
+
case 'cfIcon': {
|
|
396
|
+
const icon = parseCfIcon(attrs);
|
|
397
|
+
if (icon === undefined)
|
|
398
|
+
rule.icons = undefined;
|
|
399
|
+
else
|
|
400
|
+
rule.icons?.push(icon);
|
|
401
|
+
break;
|
|
402
|
+
}
|
|
403
|
+
case 'dxf':
|
|
404
|
+
if (selfClosing)
|
|
405
|
+
rule.dxf = '<dxf/>';
|
|
406
|
+
else
|
|
407
|
+
dxf = new DxfCapture();
|
|
408
|
+
break;
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
const closeExtension = (ln) => {
|
|
412
|
+
const id = x14IdCapture.close(ln);
|
|
413
|
+
if (id !== undefined) {
|
|
414
|
+
if (draft !== undefined)
|
|
415
|
+
draft.x14Id = id;
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
const text = extCapture.close(ln);
|
|
419
|
+
if (text !== undefined) {
|
|
420
|
+
if (ln === 'sqref')
|
|
421
|
+
extSqref = text;
|
|
422
|
+
else if (extCfvo !== undefined)
|
|
423
|
+
extCfvo.value = anchorValue(extCfvo.type, text, definedNames);
|
|
424
|
+
else
|
|
425
|
+
extRule?.draft.formulae.push(coerceNumericLiteral(unmangleFunctions(text, definedNames)));
|
|
426
|
+
}
|
|
427
|
+
else if (ln === 'cfvo') {
|
|
428
|
+
extCfvo = undefined;
|
|
429
|
+
}
|
|
430
|
+
else if (ln === 'cfRule') {
|
|
431
|
+
closeExtensionRule();
|
|
432
|
+
}
|
|
433
|
+
else if (ln === 'conditionalFormatting' && extRules !== undefined) {
|
|
434
|
+
if (extRules.length > 0)
|
|
435
|
+
blocks.push({ ref: extSqref, rules: extRules, extended: true });
|
|
436
|
+
extRules = undefined;
|
|
437
|
+
}
|
|
438
|
+
};
|
|
180
439
|
const handlers = {
|
|
181
440
|
onOpen(name, attrs, selfClosing, scope) {
|
|
441
|
+
if (dxf !== undefined) {
|
|
442
|
+
dxf.open(name, attrs, selfClosing, scope);
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
182
445
|
const ln = localName(name);
|
|
183
446
|
if (isExtensionElement(scope, name)) {
|
|
184
|
-
|
|
185
|
-
x14IdCapture.open(ln, selfClosing);
|
|
186
|
-
}
|
|
187
|
-
else if (ln === 'cfRule') {
|
|
188
|
-
x14Ext = attrs.type === 'dataBar' && attrs.id !== undefined ? emptyExt() : undefined;
|
|
189
|
-
x14ExtId = attrs.id;
|
|
190
|
-
}
|
|
191
|
-
else if (x14Ext !== undefined && ln === 'dataBar') {
|
|
192
|
-
x14Ext.gradient = boolPresent(attrs.gradient);
|
|
193
|
-
}
|
|
194
|
-
else if (x14Ext !== undefined && ln === 'negativeFillColor') {
|
|
195
|
-
x14Ext.negativeFillColor = parseColor(attrs);
|
|
196
|
-
}
|
|
197
|
-
else if (x14Ext !== undefined && ln === 'axisColor') {
|
|
198
|
-
x14Ext.axisColor = parseColor(attrs);
|
|
199
|
-
}
|
|
447
|
+
openExtension(ln, attrs, selfClosing);
|
|
200
448
|
return;
|
|
201
449
|
}
|
|
202
450
|
if (ln === 'conditionalFormatting') {
|
|
@@ -217,10 +465,12 @@ export function conditionalFormattingPass() {
|
|
|
217
465
|
(ln === 'dataBar' || ln === 'colorScale' || ln === 'iconSet')) {
|
|
218
466
|
scale = ln;
|
|
219
467
|
if (ln === 'iconSet')
|
|
220
|
-
draft
|
|
468
|
+
readIconSetAttrs(draft, attrs);
|
|
469
|
+
else if (ln === 'dataBar')
|
|
470
|
+
readDataBarAttrs(draft, attrs);
|
|
221
471
|
}
|
|
222
472
|
else if (draft !== undefined && ln === 'cfvo') {
|
|
223
|
-
draft.cfvo.push(parseCfvo(attrs));
|
|
473
|
+
draft.cfvo.push(parseCfvo(attrs, definedNames));
|
|
224
474
|
}
|
|
225
475
|
else if (draft !== undefined && ln === 'color') {
|
|
226
476
|
const color = parseColor(attrs);
|
|
@@ -236,26 +486,27 @@ export function conditionalFormattingPass() {
|
|
|
236
486
|
onText(chunk) {
|
|
237
487
|
formulaCapture.text(chunk);
|
|
238
488
|
x14IdCapture.text(chunk);
|
|
489
|
+
extCapture.text(chunk);
|
|
239
490
|
},
|
|
240
491
|
onClose(name, scope) {
|
|
492
|
+
if (dxf !== undefined) {
|
|
493
|
+
if (dxf.close(name)) {
|
|
494
|
+
if (extRule !== undefined)
|
|
495
|
+
extRule.draft.dxf = dxf.fragment;
|
|
496
|
+
dxf = undefined;
|
|
497
|
+
}
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
241
500
|
const ln = localName(name);
|
|
242
501
|
if (isExtensionElement(scope, name)) {
|
|
243
|
-
|
|
244
|
-
if (id !== undefined) {
|
|
245
|
-
if (draft !== undefined)
|
|
246
|
-
draft.x14Id = id;
|
|
247
|
-
}
|
|
248
|
-
else if (ln === 'cfRule' && x14Ext !== undefined && x14ExtId !== undefined) {
|
|
249
|
-
extById.set(x14ExtId, x14Ext);
|
|
250
|
-
x14Ext = undefined;
|
|
251
|
-
x14ExtId = undefined;
|
|
252
|
-
}
|
|
502
|
+
closeExtension(ln);
|
|
253
503
|
return;
|
|
254
504
|
}
|
|
255
505
|
const formula = formulaCapture.close(ln);
|
|
256
506
|
if (formula !== undefined) {
|
|
257
|
-
if (draft !== undefined)
|
|
258
|
-
draft.formulae.push(coerceNumericLiteral(formula));
|
|
507
|
+
if (draft !== undefined) {
|
|
508
|
+
draft.formulae.push(coerceNumericLiteral(unmangleFunctions(formula, definedNames)));
|
|
509
|
+
}
|
|
259
510
|
}
|
|
260
511
|
else if (ln === 'dataBar' || ln === 'colorScale' || ln === 'iconSet') {
|
|
261
512
|
scale = undefined;
|
|
@@ -265,8 +516,10 @@ export function conditionalFormattingPass() {
|
|
|
265
516
|
if (rule !== undefined) {
|
|
266
517
|
if (block !== undefined)
|
|
267
518
|
block.rules.push(rule);
|
|
268
|
-
if (draft.x14Id !== undefined)
|
|
519
|
+
if (draft.x14Id !== undefined) {
|
|
269
520
|
linked.push({ rule, id: draft.x14Id });
|
|
521
|
+
linkedIds.add(draft.x14Id);
|
|
522
|
+
}
|
|
270
523
|
}
|
|
271
524
|
draft = undefined;
|
|
272
525
|
}
|
|
@@ -281,47 +534,77 @@ export function conditionalFormattingPass() {
|
|
|
281
534
|
const ext = extById.get(id);
|
|
282
535
|
if (ext === undefined)
|
|
283
536
|
continue;
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
rule.negativeFillColor = ext.negativeFillColor;
|
|
288
|
-
if (ext.axisColor !== undefined)
|
|
289
|
-
rule.axisColor = ext.axisColor;
|
|
537
|
+
Object.assign(rule, ext.bar);
|
|
538
|
+
if (ext.cfvo.length > 0)
|
|
539
|
+
rule.cfvo = [...ext.cfvo];
|
|
290
540
|
}
|
|
291
541
|
return blocks;
|
|
292
542
|
};
|
|
293
543
|
return { handlers, result };
|
|
294
544
|
}
|
|
295
|
-
function
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
545
|
+
export function applyConditionalFormattings(sheet, blocks) {
|
|
546
|
+
for (const block of blocks) {
|
|
547
|
+
if (decodeSqrefRects(block.ref).length === 0)
|
|
548
|
+
continue;
|
|
549
|
+
admitting(() => {
|
|
550
|
+
sheet.addConditionalFormatting(block);
|
|
551
|
+
});
|
|
552
|
+
}
|
|
301
553
|
}
|
|
302
554
|
function newDraft(attrs) {
|
|
303
555
|
return {
|
|
304
556
|
type: enumToken(attrs.type, isConditionalFormattingType),
|
|
305
|
-
priority:
|
|
557
|
+
priority: numInteger(attrs.priority),
|
|
306
558
|
stopIfTrue: boolStrict(attrs.stopIfTrue),
|
|
307
559
|
operator: enumToken(attrs.operator, isConditionalFormattingOperator),
|
|
308
560
|
text: attrs.text,
|
|
309
561
|
timePeriod: enumToken(attrs.timePeriod, isCfTimePeriod),
|
|
310
|
-
rank:
|
|
311
|
-
stdDev:
|
|
562
|
+
rank: numInteger(attrs.rank, 0),
|
|
563
|
+
stdDev: numInteger(attrs.stdDev),
|
|
312
564
|
percent: boolStrict(attrs.percent),
|
|
313
565
|
bottom: boolStrict(attrs.bottom),
|
|
314
|
-
aboveAverage:
|
|
566
|
+
aboveAverage: boolTristate(attrs.aboveAverage),
|
|
315
567
|
equalAverage: boolStrict(attrs.equalAverage),
|
|
316
568
|
dxfId: parseIndexAttr(attrs.dxfId),
|
|
317
569
|
iconSet: undefined,
|
|
570
|
+
icons: [],
|
|
571
|
+
reverse: false,
|
|
572
|
+
showValue: undefined,
|
|
318
573
|
formulae: [],
|
|
319
574
|
cfvo: [],
|
|
320
575
|
colors: [],
|
|
321
576
|
color: undefined,
|
|
577
|
+
bar: {},
|
|
322
578
|
x14Id: undefined,
|
|
579
|
+
dxf: undefined,
|
|
323
580
|
};
|
|
324
581
|
}
|
|
582
|
+
function readIconSetAttrs(draft, attrs) {
|
|
583
|
+
draft.iconSet = enumToken(attrs.iconSet, isIconSetType);
|
|
584
|
+
draft.showValue = boolTristate(attrs.showValue);
|
|
585
|
+
draft.reverse = boolStrict(attrs.reverse);
|
|
586
|
+
}
|
|
587
|
+
function readDataBarAttrs(draft, attrs) {
|
|
588
|
+
const { bar } = draft;
|
|
589
|
+
draft.showValue = boolTristate(attrs.showValue);
|
|
590
|
+
setDefined(bar, 'minLength', numInteger(attrs.minLength, 0));
|
|
591
|
+
setDefined(bar, 'maxLength', numInteger(attrs.maxLength, 0));
|
|
592
|
+
setDefined(bar, 'border', boolTristate(attrs.border));
|
|
593
|
+
setDefined(bar, 'gradient', boolTristate(attrs.gradient));
|
|
594
|
+
setDefined(bar, 'direction', enumToken(attrs.direction, isDataBarDirection));
|
|
595
|
+
setDefined(bar, 'negativeBarColorSameAsPositive', boolTristate(attrs.negativeBarColorSameAsPositive));
|
|
596
|
+
setDefined(bar, 'negativeBarBorderColorSameAsPositive', boolTristate(attrs.negativeBarBorderColorSameAsPositive));
|
|
597
|
+
setDefined(bar, 'axisPosition', enumToken(attrs.axisPosition, isDataBarAxisPosition));
|
|
598
|
+
}
|
|
599
|
+
function setDefined(bar, key, value) {
|
|
600
|
+
if (value !== undefined)
|
|
601
|
+
bar[key] = value;
|
|
602
|
+
}
|
|
603
|
+
function parseCfIcon(attrs) {
|
|
604
|
+
const iconSet = enumToken(attrs.iconSet, isCfIconSetType);
|
|
605
|
+
const iconId = numInteger(attrs.iconId, 0);
|
|
606
|
+
return iconSet === undefined || iconId === undefined ? undefined : { iconSet, iconId };
|
|
607
|
+
}
|
|
325
608
|
function dxfIndex(value) {
|
|
326
609
|
return numInteger(value, 0);
|
|
327
610
|
}
|
|
@@ -358,6 +641,12 @@ function finalizeRule(draft) {
|
|
|
358
641
|
rule.dxfId = draft.dxfId;
|
|
359
642
|
if (draft.iconSet !== undefined)
|
|
360
643
|
rule.iconSet = draft.iconSet;
|
|
644
|
+
if (draft.icons !== undefined && draft.icons.length > 0)
|
|
645
|
+
rule.icons = draft.icons;
|
|
646
|
+
if (draft.reverse)
|
|
647
|
+
rule.reverse = true;
|
|
648
|
+
if (draft.showValue === false)
|
|
649
|
+
rule.showValue = false;
|
|
361
650
|
if (draft.formulae.length > 0)
|
|
362
651
|
rule.formulae = draft.formulae;
|
|
363
652
|
if (draft.cfvo.length > 0)
|
|
@@ -366,14 +655,20 @@ function finalizeRule(draft) {
|
|
|
366
655
|
rule.colors = draft.colors;
|
|
367
656
|
if (draft.color !== undefined)
|
|
368
657
|
rule.color = draft.color;
|
|
658
|
+
if (draft.type === 'dataBar')
|
|
659
|
+
Object.assign(rule, draft.bar);
|
|
369
660
|
return rule;
|
|
370
661
|
}
|
|
371
|
-
function parseCfvo(attrs) {
|
|
662
|
+
function parseCfvo(attrs, definedNames) {
|
|
372
663
|
const raw = attrs.type;
|
|
373
664
|
const type = raw !== undefined && isCfValueObjectType(raw) ? raw : 'num';
|
|
374
665
|
const cfvo = { type };
|
|
375
|
-
if (attrs.val !== undefined)
|
|
376
|
-
cfvo.value = type
|
|
377
|
-
|
|
666
|
+
if (attrs.val !== undefined)
|
|
667
|
+
cfvo.value = anchorValue(type, attrs.val, definedNames);
|
|
668
|
+
if (boolTristate(attrs.gte) === false)
|
|
669
|
+
cfvo.gte = false;
|
|
378
670
|
return cfvo;
|
|
379
671
|
}
|
|
672
|
+
function anchorValue(type, text, definedNames) {
|
|
673
|
+
return type === 'formula' ? unmangleFunctions(text, definedNames) : coerceNumericLiteral(text);
|
|
674
|
+
}
|