@trebco/treb 23.6.5 → 25.0.0-rc1
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/.eslintignore +8 -0
- package/.eslintrc.js +164 -0
- package/README-shadow-DOM.md +88 -0
- package/README.md +37 -130
- package/api-config.json +29 -0
- package/api-generator/api-generator-types.ts +82 -0
- package/api-generator/api-generator.ts +1172 -0
- package/api-generator/package.json +3 -0
- package/build/treb-spreadsheet.mjs +14 -0
- package/{treb.d.ts → build/treb.d.ts} +285 -269
- package/esbuild-custom-element.mjs +336 -0
- package/esbuild.js +305 -0
- package/package.json +43 -14
- package/treb-base-types/package.json +5 -0
- package/treb-base-types/src/api_types.ts +36 -0
- package/treb-base-types/src/area.ts +583 -0
- package/treb-base-types/src/basic_types.ts +45 -0
- package/treb-base-types/src/cell.ts +612 -0
- package/treb-base-types/src/cells.ts +1066 -0
- package/treb-base-types/src/color.ts +124 -0
- package/treb-base-types/src/import.ts +71 -0
- package/treb-base-types/src/index-standalone.ts +29 -0
- package/treb-base-types/src/index.ts +42 -0
- package/treb-base-types/src/layout.ts +47 -0
- package/treb-base-types/src/localization.ts +187 -0
- package/treb-base-types/src/rectangle.ts +145 -0
- package/treb-base-types/src/render_text.ts +72 -0
- package/treb-base-types/src/style.ts +545 -0
- package/treb-base-types/src/table.ts +109 -0
- package/treb-base-types/src/text_part.ts +54 -0
- package/treb-base-types/src/theme.ts +608 -0
- package/treb-base-types/src/union.ts +152 -0
- package/treb-base-types/src/value-type.ts +164 -0
- package/treb-base-types/style/resizable.css +59 -0
- package/treb-calculator/modern.tsconfig.json +11 -0
- package/treb-calculator/package.json +5 -0
- package/treb-calculator/src/calculator.ts +2546 -0
- package/treb-calculator/src/complex-math.ts +558 -0
- package/treb-calculator/src/dag/array-vertex.ts +198 -0
- package/treb-calculator/src/dag/graph.ts +951 -0
- package/treb-calculator/src/dag/leaf_vertex.ts +118 -0
- package/treb-calculator/src/dag/spreadsheet_vertex.ts +327 -0
- package/treb-calculator/src/dag/spreadsheet_vertex_base.ts +44 -0
- package/treb-calculator/src/dag/vertex.ts +352 -0
- package/treb-calculator/src/descriptors.ts +162 -0
- package/treb-calculator/src/expression-calculator.ts +1069 -0
- package/treb-calculator/src/function-error.ts +103 -0
- package/treb-calculator/src/function-library.ts +103 -0
- package/treb-calculator/src/functions/base-functions.ts +1214 -0
- package/treb-calculator/src/functions/checkbox.ts +164 -0
- package/treb-calculator/src/functions/complex-functions.ts +253 -0
- package/treb-calculator/src/functions/finance-functions.ts +399 -0
- package/treb-calculator/src/functions/information-functions.ts +102 -0
- package/treb-calculator/src/functions/matrix-functions.ts +182 -0
- package/treb-calculator/src/functions/sparkline.ts +335 -0
- package/treb-calculator/src/functions/statistics-functions.ts +350 -0
- package/treb-calculator/src/functions/text-functions.ts +298 -0
- package/treb-calculator/src/index.ts +27 -0
- package/treb-calculator/src/notifier-types.ts +59 -0
- package/treb-calculator/src/primitives.ts +428 -0
- package/treb-calculator/src/utilities.ts +305 -0
- package/treb-charts/package.json +5 -0
- package/treb-charts/src/chart-functions.ts +156 -0
- package/treb-charts/src/chart-types.ts +230 -0
- package/treb-charts/src/chart.ts +1288 -0
- package/treb-charts/src/index.ts +24 -0
- package/treb-charts/src/main.ts +37 -0
- package/treb-charts/src/rectangle.ts +52 -0
- package/treb-charts/src/renderer.ts +1841 -0
- package/treb-charts/src/util.ts +122 -0
- package/treb-charts/style/charts.scss +221 -0
- package/treb-charts/style/old-charts.scss +250 -0
- package/treb-embed/markup/layout.html +137 -0
- package/treb-embed/markup/toolbar.html +175 -0
- package/treb-embed/modern.tsconfig.json +25 -0
- package/treb-embed/src/custom-element/content-types.d.ts +18 -0
- package/treb-embed/src/custom-element/global.d.ts +11 -0
- package/treb-embed/src/custom-element/spreadsheet-constructor.ts +1227 -0
- package/treb-embed/src/custom-element/treb-global.ts +44 -0
- package/treb-embed/src/custom-element/treb-spreadsheet-element.ts +52 -0
- package/treb-embed/src/embedded-spreadsheet.ts +5362 -0
- package/treb-embed/src/index.ts +16 -0
- package/treb-embed/src/language-model.ts +41 -0
- package/treb-embed/src/options.ts +320 -0
- package/treb-embed/src/progress-dialog.ts +228 -0
- package/treb-embed/src/selection-state.ts +16 -0
- package/treb-embed/src/spinner.ts +42 -0
- package/treb-embed/src/toolbar-message.ts +96 -0
- package/treb-embed/src/types.ts +167 -0
- package/treb-embed/style/autocomplete.scss +103 -0
- package/treb-embed/style/dark-theme.scss +114 -0
- package/treb-embed/style/defaults.scss +36 -0
- package/treb-embed/style/dialog.scss +181 -0
- package/treb-embed/style/dropdown-select.scss +101 -0
- package/treb-embed/style/formula-bar.scss +193 -0
- package/treb-embed/style/grid.scss +374 -0
- package/treb-embed/style/layout.scss +424 -0
- package/treb-embed/style/mouse-mask.scss +67 -0
- package/treb-embed/style/note.scss +92 -0
- package/treb-embed/style/overlay-editor.scss +102 -0
- package/treb-embed/style/spinner.scss +92 -0
- package/treb-embed/style/tab-bar.scss +228 -0
- package/treb-embed/style/table.scss +80 -0
- package/treb-embed/style/theme-defaults.scss +444 -0
- package/treb-embed/style/toolbar.scss +416 -0
- package/treb-embed/style/tooltip.scss +68 -0
- package/treb-embed/style/treb-icons.scss +130 -0
- package/treb-embed/style/treb-spreadsheet-element.scss +20 -0
- package/treb-embed/style/z-index.scss +43 -0
- package/treb-export/docs/charts.md +68 -0
- package/treb-export/modern.tsconfig.json +19 -0
- package/treb-export/package.json +4 -0
- package/treb-export/src/address-type.ts +77 -0
- package/treb-export/src/base-template.ts +22 -0
- package/treb-export/src/column-width.ts +85 -0
- package/treb-export/src/drawing2/chart-template-components2.ts +389 -0
- package/treb-export/src/drawing2/chart2.ts +282 -0
- package/treb-export/src/drawing2/column-chart-template2.ts +521 -0
- package/treb-export/src/drawing2/donut-chart-template2.ts +296 -0
- package/treb-export/src/drawing2/drawing2.ts +355 -0
- package/treb-export/src/drawing2/embedded-image.ts +71 -0
- package/treb-export/src/drawing2/scatter-chart-template2.ts +555 -0
- package/treb-export/src/export-worker/export-worker.ts +99 -0
- package/treb-export/src/export-worker/index-modern.ts +22 -0
- package/treb-export/src/export2.ts +2204 -0
- package/treb-export/src/import2.ts +882 -0
- package/treb-export/src/relationship.ts +36 -0
- package/treb-export/src/shared-strings2.ts +128 -0
- package/treb-export/src/template-2.ts +22 -0
- package/treb-export/src/unescape_xml.ts +47 -0
- package/treb-export/src/workbook-sheet2.ts +182 -0
- package/treb-export/src/workbook-style2.ts +1285 -0
- package/treb-export/src/workbook-theme2.ts +88 -0
- package/treb-export/src/workbook2.ts +491 -0
- package/treb-export/src/xml-utils.ts +201 -0
- package/treb-export/template/base/[Content_Types].xml +2 -0
- package/treb-export/template/base/_rels/.rels +2 -0
- package/treb-export/template/base/docProps/app.xml +2 -0
- package/treb-export/template/base/docProps/core.xml +12 -0
- package/treb-export/template/base/xl/_rels/workbook.xml.rels +2 -0
- package/treb-export/template/base/xl/sharedStrings.xml +2 -0
- package/treb-export/template/base/xl/styles.xml +2 -0
- package/treb-export/template/base/xl/theme/theme1.xml +2 -0
- package/treb-export/template/base/xl/workbook.xml +2 -0
- package/treb-export/template/base/xl/worksheets/sheet1.xml +2 -0
- package/treb-export/template/base.xlsx +0 -0
- package/treb-format/package.json +8 -0
- package/treb-format/src/format.test.ts +213 -0
- package/treb-format/src/format.ts +942 -0
- package/treb-format/src/format_cache.ts +199 -0
- package/treb-format/src/format_parser.ts +723 -0
- package/treb-format/src/index.ts +25 -0
- package/treb-format/src/number_format_section.ts +100 -0
- package/treb-format/src/value_parser.ts +337 -0
- package/treb-grid/package.json +5 -0
- package/treb-grid/src/editors/autocomplete.ts +394 -0
- package/treb-grid/src/editors/autocomplete_matcher.ts +260 -0
- package/treb-grid/src/editors/formula_bar.ts +473 -0
- package/treb-grid/src/editors/formula_editor_base.ts +910 -0
- package/treb-grid/src/editors/overlay_editor.ts +511 -0
- package/treb-grid/src/index.ts +37 -0
- package/treb-grid/src/layout/base_layout.ts +2618 -0
- package/treb-grid/src/layout/grid_layout.ts +299 -0
- package/treb-grid/src/layout/rectangle_cache.ts +86 -0
- package/treb-grid/src/render/selection-renderer.ts +414 -0
- package/treb-grid/src/render/svg_header_overlay.ts +93 -0
- package/treb-grid/src/render/svg_selection_block.ts +187 -0
- package/treb-grid/src/render/tile_renderer.ts +2122 -0
- package/treb-grid/src/types/annotation.ts +216 -0
- package/treb-grid/src/types/border_constants.ts +34 -0
- package/treb-grid/src/types/clipboard_data.ts +31 -0
- package/treb-grid/src/types/data_model.ts +334 -0
- package/treb-grid/src/types/drag_mask.ts +81 -0
- package/treb-grid/src/types/grid.ts +7743 -0
- package/treb-grid/src/types/grid_base.ts +3644 -0
- package/treb-grid/src/types/grid_command.ts +470 -0
- package/treb-grid/src/types/grid_events.ts +124 -0
- package/treb-grid/src/types/grid_options.ts +97 -0
- package/treb-grid/src/types/grid_selection.ts +60 -0
- package/treb-grid/src/types/named_range.ts +369 -0
- package/treb-grid/src/types/scale-control.ts +202 -0
- package/treb-grid/src/types/serialize_options.ts +72 -0
- package/treb-grid/src/types/set_range_options.ts +52 -0
- package/treb-grid/src/types/sheet.ts +3099 -0
- package/treb-grid/src/types/sheet_types.ts +95 -0
- package/treb-grid/src/types/tab_bar.ts +464 -0
- package/treb-grid/src/types/tile.ts +59 -0
- package/treb-grid/src/types/update_flags.ts +75 -0
- package/treb-grid/src/util/dom_utilities.ts +44 -0
- package/treb-grid/src/util/fontmetrics2.ts +179 -0
- package/treb-grid/src/util/ua.ts +104 -0
- package/treb-logo.svg +18 -0
- package/treb-parser/package.json +5 -0
- package/treb-parser/src/csv-parser.ts +122 -0
- package/treb-parser/src/index.ts +25 -0
- package/treb-parser/src/md-parser.ts +526 -0
- package/treb-parser/src/parser-types.ts +397 -0
- package/treb-parser/src/parser.test.ts +298 -0
- package/treb-parser/src/parser.ts +2673 -0
- package/treb-utils/package.json +5 -0
- package/treb-utils/src/dispatch.ts +57 -0
- package/treb-utils/src/event_source.ts +147 -0
- package/treb-utils/src/ievent_source.ts +33 -0
- package/treb-utils/src/index.ts +31 -0
- package/treb-utils/src/measurement.ts +174 -0
- package/treb-utils/src/resizable.ts +160 -0
- package/treb-utils/src/scale.ts +137 -0
- package/treb-utils/src/serialize_html.ts +124 -0
- package/treb-utils/src/template.ts +70 -0
- package/treb-utils/src/validate_uri.ts +61 -0
- package/tsconfig.json +10 -0
- package/tsproject.json +30 -0
- package/util/license-plugin-esbuild.js +86 -0
- package/util/list-css-vars.sh +46 -0
- package/README-esm.md +0 -37
- package/treb-bundle.css +0 -2
- package/treb-bundle.mjs +0 -15
|
@@ -0,0 +1,1285 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of TREB.
|
|
3
|
+
*
|
|
4
|
+
* TREB is free software: you can redistribute it and/or modify it under the
|
|
5
|
+
* terms of the GNU General Public License as published by the Free Software
|
|
6
|
+
* Foundation, either version 3 of the License, or (at your option) any
|
|
7
|
+
* later version.
|
|
8
|
+
*
|
|
9
|
+
* TREB is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
10
|
+
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
11
|
+
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
12
|
+
* details.
|
|
13
|
+
*
|
|
14
|
+
* You should have received a copy of the GNU General Public License along
|
|
15
|
+
* with TREB. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
*
|
|
17
|
+
* Copyright 2022-2023 trebco, llc.
|
|
18
|
+
* info@treb.app
|
|
19
|
+
*
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
// import * as ElementTree from 'elementtree';
|
|
23
|
+
// import { Element, ElementTree as Tree } from 'elementtree';
|
|
24
|
+
|
|
25
|
+
import { Style } from 'treb-base-types';
|
|
26
|
+
import { Theme } from './workbook-theme2';
|
|
27
|
+
import { NumberFormatCache } from 'treb-format';
|
|
28
|
+
import { XMLUtils } from './xml-utils';
|
|
29
|
+
|
|
30
|
+
import { Unescape } from './unescape_xml';
|
|
31
|
+
|
|
32
|
+
export interface Font {
|
|
33
|
+
size?: number;
|
|
34
|
+
name?: string;
|
|
35
|
+
family?: number;
|
|
36
|
+
color_theme?: number;
|
|
37
|
+
color_argb?: string;
|
|
38
|
+
color_tint?: number;
|
|
39
|
+
scheme?: string;
|
|
40
|
+
bold?: boolean;
|
|
41
|
+
italic?: boolean;
|
|
42
|
+
underline?: boolean;
|
|
43
|
+
strike?: boolean;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface NumberFormat {
|
|
47
|
+
id?: number;
|
|
48
|
+
symbolic_name?: string;
|
|
49
|
+
format?: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface XlColor {
|
|
53
|
+
theme?: number;
|
|
54
|
+
tint?: number;
|
|
55
|
+
indexed?: number;
|
|
56
|
+
argb?: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface Fill {
|
|
60
|
+
pattern_type: 'none'|'solid'|'gray';
|
|
61
|
+
pattern_gray?: number;
|
|
62
|
+
fg_color?: XlColor;
|
|
63
|
+
bg_color?: XlColor;
|
|
64
|
+
// color_argb?: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface CellXf {
|
|
68
|
+
number_format: number;
|
|
69
|
+
font: number;
|
|
70
|
+
fill: number;
|
|
71
|
+
border: number;
|
|
72
|
+
wrap_text?: boolean;
|
|
73
|
+
horizontal_alignment?: string;
|
|
74
|
+
vertical_alignment?: string;
|
|
75
|
+
xfid?: number;
|
|
76
|
+
|
|
77
|
+
// FIXME // apply_font?: boolean;
|
|
78
|
+
// FIXME // apply_border?: boolean;
|
|
79
|
+
// FIXME // apply_number_format?: boolean;
|
|
80
|
+
// FIXME // apply_alignment?: boolean;
|
|
81
|
+
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
interface ColorAttributes {
|
|
85
|
+
indexed?: string;
|
|
86
|
+
rgb?: string;
|
|
87
|
+
theme?: string;
|
|
88
|
+
tint?: string;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface BorderEdge {
|
|
92
|
+
style?: string;
|
|
93
|
+
color?: number; // indexed
|
|
94
|
+
rgba?: string;
|
|
95
|
+
theme?: number;
|
|
96
|
+
tint?: number;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* this is flat so we can map/copy better, even thought it makes
|
|
101
|
+
* more sense as a map of simple objects
|
|
102
|
+
*/
|
|
103
|
+
export interface BorderStyle {
|
|
104
|
+
|
|
105
|
+
top: BorderEdge,
|
|
106
|
+
left: BorderEdge,
|
|
107
|
+
bottom: BorderEdge,
|
|
108
|
+
right: BorderEdge,
|
|
109
|
+
diagonal: BorderEdge,
|
|
110
|
+
|
|
111
|
+
/*
|
|
112
|
+
left_style?: string; // 'thin' | ??
|
|
113
|
+
left_color?: number; // indexed // FIXME: argb
|
|
114
|
+
left_color_rgba?: string;
|
|
115
|
+
left_color_theme?: number;
|
|
116
|
+
left_color_tint?: number;
|
|
117
|
+
|
|
118
|
+
right_style?: string;
|
|
119
|
+
right_color?: number;
|
|
120
|
+
right_color_rgba?: string;
|
|
121
|
+
right_color_theme?: number;
|
|
122
|
+
right_color_tint?: number;
|
|
123
|
+
|
|
124
|
+
top_style?: string;
|
|
125
|
+
top_color?: number;
|
|
126
|
+
top_color_rgba?: string;
|
|
127
|
+
top_color_theme?: number;
|
|
128
|
+
top_color_tint?: number;
|
|
129
|
+
|
|
130
|
+
bottom_style?: string;
|
|
131
|
+
bottom_color?: number;
|
|
132
|
+
bottom_color_rgba?: string;
|
|
133
|
+
bottom_color_theme?: number;
|
|
134
|
+
bottom_color_tint?: number;
|
|
135
|
+
|
|
136
|
+
diagonal_style?: string;
|
|
137
|
+
diagonal_color?: number;
|
|
138
|
+
diagonal_color_rgba?: string;
|
|
139
|
+
diagonal_color_theme?: number;
|
|
140
|
+
diagonal_color_tint?: number;
|
|
141
|
+
*/
|
|
142
|
+
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const default_border = {
|
|
146
|
+
top: {}, left: {}, bottom: {}, right: {}, diagonal: {},
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export interface StyleOptions {
|
|
150
|
+
font?: Font;
|
|
151
|
+
border?: BorderStyle;
|
|
152
|
+
number_format?: NumberFormat;
|
|
153
|
+
horizontal_alignment?: string;
|
|
154
|
+
vertical_alignment?: string;
|
|
155
|
+
wrap?: boolean;
|
|
156
|
+
fill?: Fill;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
export class StyleCache {
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* thanks to
|
|
164
|
+
* http://polymathprogrammer.com/2011/02/15/built-in-styles-for-excel-open-xml/
|
|
165
|
+
*/
|
|
166
|
+
public static default_styles: {[index: number]: string} = {
|
|
167
|
+
0: 'General',
|
|
168
|
+
1: '0',
|
|
169
|
+
2: '0.00',
|
|
170
|
+
3: '#,##0',
|
|
171
|
+
4: '#,##0.00',
|
|
172
|
+
9: '0%',
|
|
173
|
+
10: '0.00%',
|
|
174
|
+
11: '0.00E+00',
|
|
175
|
+
12: '# ?/?',
|
|
176
|
+
13: '# ??/??',
|
|
177
|
+
14: 'mm-dd-yy',
|
|
178
|
+
15: 'd-mmm-yy',
|
|
179
|
+
16: 'd-mmm',
|
|
180
|
+
17: 'mmm-yy',
|
|
181
|
+
18: 'h:mm AM/PM',
|
|
182
|
+
19: 'h:mm:ss AM/PM',
|
|
183
|
+
20: 'h:mm',
|
|
184
|
+
21: 'h:mm:ss',
|
|
185
|
+
22: 'm/d/yy h:mm',
|
|
186
|
+
37: '#,##0 ;(#,##0)',
|
|
187
|
+
38: '#,##0 ;[Red](#,##0)',
|
|
188
|
+
39: '#,##0.00;(#,##0.00)',
|
|
189
|
+
40: '#,##0.00;[Red](#,##0.00)',
|
|
190
|
+
45: 'mm:ss',
|
|
191
|
+
46: '[h]:mm:ss',
|
|
192
|
+
47: 'mmss.0',
|
|
193
|
+
48: '##0.0E+0',
|
|
194
|
+
49: '@',
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
public theme = new Theme();
|
|
198
|
+
|
|
199
|
+
public cell_xfs: CellXf[] = [];
|
|
200
|
+
public fonts: Font[] = [];
|
|
201
|
+
public borders: BorderStyle[] = [];
|
|
202
|
+
public fills: Fill[] = [];
|
|
203
|
+
public number_formats: NumberFormat[] = [];
|
|
204
|
+
public base_number_format_id = 200; // ?
|
|
205
|
+
|
|
206
|
+
// public dom?: Tree;
|
|
207
|
+
|
|
208
|
+
public modified = false;
|
|
209
|
+
|
|
210
|
+
public Clamp(value: number, min: number, max: number): number {
|
|
211
|
+
return Math.max(min, Math.min(value, max));
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
public TintColor(base: string, tint: number): string {
|
|
215
|
+
|
|
216
|
+
let r = parseInt(base.substr(0, 2), 16);
|
|
217
|
+
let g = parseInt(base.substr(2, 2), 16);
|
|
218
|
+
let b = parseInt(base.substr(4, 2), 16);
|
|
219
|
+
|
|
220
|
+
if (tint < 0) {
|
|
221
|
+
r = Math.round(r * tint + r);
|
|
222
|
+
g = Math.round(g * tint + g);
|
|
223
|
+
b = Math.round(b * tint + b);
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
r = Math.round((255 - r) * tint + r);
|
|
227
|
+
g = Math.round((255 - g) * tint + g);
|
|
228
|
+
b = Math.round((255 - b) * tint + b);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return [r, g, b].map((x) => {
|
|
232
|
+
const s = this.Clamp(x, 0, 255).toString(16);
|
|
233
|
+
return s.length < 2 ? ('0' + s) : s;
|
|
234
|
+
}).join('');
|
|
235
|
+
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
///
|
|
239
|
+
|
|
240
|
+
public StyleOptionsFromProperties(source: Style.Properties): StyleOptions {
|
|
241
|
+
|
|
242
|
+
const composite: Style.Properties = // Style.Composite(list);
|
|
243
|
+
JSON.parse(JSON.stringify(source));
|
|
244
|
+
|
|
245
|
+
for (const key of Object.keys(composite) as Style.PropertyKeys[]) {
|
|
246
|
+
if (composite[key] === 'none') {
|
|
247
|
+
delete composite[key];
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const font: Font = {};
|
|
252
|
+
const fill: Fill = { pattern_type: 'none' };
|
|
253
|
+
const border: BorderStyle = JSON.parse(JSON.stringify(default_border));
|
|
254
|
+
|
|
255
|
+
const options: StyleOptions = {
|
|
256
|
+
font, border,
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
if (composite.number_format) {
|
|
260
|
+
|
|
261
|
+
// we have some symbolic number formats that we'll need to
|
|
262
|
+
// translate. these are defined by the cache.
|
|
263
|
+
|
|
264
|
+
options.number_format = {
|
|
265
|
+
format: NumberFormatCache.Translate(composite.number_format),
|
|
266
|
+
symbolic_name: composite.number_format, // for reference later
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (composite.font_size?.unit && composite.font_size.value) {
|
|
272
|
+
if (composite.font_size.unit !== 'pt') {
|
|
273
|
+
console.warn(`can't handle non-point font (FIXME)`);
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
font.size = composite.font_size.value;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (composite.bold) font.bold = true;
|
|
281
|
+
if (composite.italic) font.italic = true;
|
|
282
|
+
if (composite.underline) font.underline = true;
|
|
283
|
+
|
|
284
|
+
//if (composite.text_color && composite.text_color !== Style.DefaultProperties.text_color) {
|
|
285
|
+
// font.color_argb = composite.text_color;
|
|
286
|
+
//}
|
|
287
|
+
|
|
288
|
+
if (composite.text) {
|
|
289
|
+
if (composite.text.text) {
|
|
290
|
+
font.color_argb = composite.text.text;
|
|
291
|
+
}
|
|
292
|
+
else if (typeof composite.text.theme === 'number') {
|
|
293
|
+
font.color_theme = composite.text.theme;
|
|
294
|
+
if (composite.text.tint) {
|
|
295
|
+
font.color_tint = composite.text.tint;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const TranslateBorder = (src: Style.CompositeBorderEdge, dest: BorderEdge) => {
|
|
301
|
+
if (src.width) {
|
|
302
|
+
dest.style = 'thin';
|
|
303
|
+
if (src.color.text) {
|
|
304
|
+
dest.rgba =src.color.text;
|
|
305
|
+
}
|
|
306
|
+
else if (typeof src.color.theme === 'number') {
|
|
307
|
+
dest.theme = src.color.theme;
|
|
308
|
+
if (src.color.tint) {
|
|
309
|
+
dest.tint = src.color.tint;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
dest.color = 64;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
const composite_borders = Style.CompositeBorders(composite);
|
|
319
|
+
TranslateBorder(composite_borders.top, border.top);
|
|
320
|
+
TranslateBorder(composite_borders.left, border.left);
|
|
321
|
+
TranslateBorder(composite_borders.right, border.right);
|
|
322
|
+
TranslateBorder(composite_borders.bottom, border.bottom);
|
|
323
|
+
|
|
324
|
+
/*
|
|
325
|
+
if (composite.border_top) { // && composite.border_top_fill) {
|
|
326
|
+
|
|
327
|
+
border.top.style = 'thin';
|
|
328
|
+
if (composite.border_top_fill?.text) {
|
|
329
|
+
border.top.rgba = composite.border_top_fill.text;
|
|
330
|
+
}
|
|
331
|
+
else if (typeof composite.border_top_fill?.theme === 'number') {
|
|
332
|
+
border.top.theme = composite.border_top_fill.theme;
|
|
333
|
+
if (composite.border_top_fill.tint) {
|
|
334
|
+
border.top.tint = composite.border_top_fill.tint;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
else {
|
|
338
|
+
border.top.color = 64;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
if (composite.border_bottom) { // && composite.border_bottom_fill) {
|
|
342
|
+
|
|
343
|
+
if (composite.border_bottom > 1) {
|
|
344
|
+
border.bottom.style = 'double';
|
|
345
|
+
}
|
|
346
|
+
else {
|
|
347
|
+
border.bottom.style = 'thin';
|
|
348
|
+
}
|
|
349
|
+
if (composite.border_bottom_fill?.text) {
|
|
350
|
+
border.bottom.rgba = composite.border_bottom_fill.text;
|
|
351
|
+
}
|
|
352
|
+
else if (typeof composite.border_bottom_fill?.theme === 'number') {
|
|
353
|
+
border.bottom.theme = composite.border_bottom_fill.theme;
|
|
354
|
+
if (composite.border_bottom_fill.tint) {
|
|
355
|
+
border.bottom.tint = composite.border_bottom_fill.tint;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
else {
|
|
359
|
+
border.bottom.color = 64;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
if (composite.border_left) { // && composite.border_left_fill) {
|
|
363
|
+
|
|
364
|
+
border.left.style = 'thin';
|
|
365
|
+
if (composite.border_left_fill?.text) {
|
|
366
|
+
border.left.rgba = composite.border_left_fill.text;
|
|
367
|
+
}
|
|
368
|
+
else if (typeof composite.border_left_fill?.theme === 'number') {
|
|
369
|
+
border.left.theme = composite.border_left_fill.theme;
|
|
370
|
+
if (composite.border_left_fill.tint) {
|
|
371
|
+
border.left.tint = composite.border_left_fill.tint;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
else {
|
|
375
|
+
border.left.color = 64;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
if (composite.border_right) { // && composite.border_right_fill) {
|
|
379
|
+
|
|
380
|
+
border.right.style = 'thin';
|
|
381
|
+
if (composite.border_right_fill?.text) {
|
|
382
|
+
border.right.rgba = composite.border_right_fill.text;
|
|
383
|
+
}
|
|
384
|
+
else if (typeof composite.border_right_fill?.theme === 'number') {
|
|
385
|
+
border.right.theme = composite.border_right_fill.theme;
|
|
386
|
+
if (composite.border_right_fill.tint) {
|
|
387
|
+
border.right.tint = composite.border_right_fill.tint;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
else {
|
|
391
|
+
border.right.color = 64;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// console.info("BXX", JSON.stringify(composite, undefined, 2), JSON.stringify(border, undefined, 2));
|
|
395
|
+
|
|
396
|
+
}
|
|
397
|
+
*/
|
|
398
|
+
|
|
399
|
+
// leave blank for bottom, default
|
|
400
|
+
|
|
401
|
+
switch (composite.vertical_align) {
|
|
402
|
+
case Style.VerticalAlign.Top:
|
|
403
|
+
options.vertical_alignment = 'top';
|
|
404
|
+
break;
|
|
405
|
+
case Style.VerticalAlign.Middle:
|
|
406
|
+
options.vertical_alignment = 'center';
|
|
407
|
+
break;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
switch (composite.horizontal_align) {
|
|
411
|
+
case Style.HorizontalAlign.Center:
|
|
412
|
+
options.horizontal_alignment = 'center';
|
|
413
|
+
break;
|
|
414
|
+
case Style.HorizontalAlign.Left:
|
|
415
|
+
options.horizontal_alignment = 'left';
|
|
416
|
+
break;
|
|
417
|
+
case Style.HorizontalAlign.Right:
|
|
418
|
+
options.horizontal_alignment = 'right';
|
|
419
|
+
break;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
if (composite.fill) {
|
|
423
|
+
fill.pattern_type = 'solid';
|
|
424
|
+
if (composite.fill.text) {
|
|
425
|
+
fill.fg_color = { argb: composite.fill.text };
|
|
426
|
+
}
|
|
427
|
+
else if (typeof composite.fill.theme === 'number') {
|
|
428
|
+
fill.fg_color = { theme: composite.fill.theme };
|
|
429
|
+
if (composite.fill.tint) {
|
|
430
|
+
fill.fg_color.tint = composite.fill.tint;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
else {
|
|
434
|
+
fill.fg_color = { theme: 1 };
|
|
435
|
+
}
|
|
436
|
+
options.fill = fill;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
if (composite.wrap) {
|
|
440
|
+
options.wrap = true;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
return options;
|
|
444
|
+
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
///
|
|
448
|
+
|
|
449
|
+
public CellXfToStyle(xf: CellXf): Style.Properties {
|
|
450
|
+
|
|
451
|
+
const props: Style.Properties = {};
|
|
452
|
+
|
|
453
|
+
// number format
|
|
454
|
+
|
|
455
|
+
let format_string = StyleCache.default_styles[xf.number_format];
|
|
456
|
+
if (!format_string) {
|
|
457
|
+
for (const candidate of this.number_formats) {
|
|
458
|
+
if (candidate.id === xf.number_format) {
|
|
459
|
+
if (candidate.format) {
|
|
460
|
+
format_string = candidate.format;
|
|
461
|
+
break;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
if (format_string) {
|
|
468
|
+
|
|
469
|
+
// Excel uses number formats like
|
|
470
|
+
|
|
471
|
+
// #,##0.00\ [$€-40C];[Red]\-#,##0.00\ [$€-40C]
|
|
472
|
+
// [$¥-411]#,##0;[Red]\-[$¥-411]#,##0
|
|
473
|
+
// _("$"* #,##0_);_("$"* \(#,##0\);_("$"* "-"??_);_(@_)
|
|
474
|
+
|
|
475
|
+
// where [$¥-411] encodes a yen symbol, [$€-40C] is the euro, &c.
|
|
476
|
+
// I have no idea what that encoding is, or where it comes from
|
|
477
|
+
// (can't find it in Excel documentation; should probably check OOo).
|
|
478
|
+
|
|
479
|
+
// for the time being we will just drop, and assume the symbol
|
|
480
|
+
// (in position 2) is correct. are we sure there are always 3 hex
|
|
481
|
+
// characters? and always negative? (...)
|
|
482
|
+
|
|
483
|
+
// OK, got it, these are Microsoft LCIDs in hex. so the format seems to be:
|
|
484
|
+
//
|
|
485
|
+
// square bracket, dollar sign, symbol, hyphen, hex LCID, square bracket
|
|
486
|
+
//
|
|
487
|
+
// we can safely drop this for now, AFAIAC. LCID seems to be (in hex)
|
|
488
|
+
// usually 3-4 digits, but I suppose lower is conceivable.
|
|
489
|
+
|
|
490
|
+
const encoding_regex = /\[\$(.)-[0-9A-Za-z]{1,4}\]/g;
|
|
491
|
+
format_string = format_string.replace(encoding_regex, '$1');
|
|
492
|
+
|
|
493
|
+
// there are also locale indicators with no symbol -- we can remove these
|
|
494
|
+
// for now, but we need to consider how to deal with them. (...)
|
|
495
|
+
|
|
496
|
+
// also this could be merged with the above.
|
|
497
|
+
|
|
498
|
+
const locale_regex = /\[\$-[0-9A-Za-z]{1,4}\]/g;
|
|
499
|
+
format_string = format_string.replace(locale_regex, '');
|
|
500
|
+
|
|
501
|
+
props.number_format = format_string;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// font attributes (atm we are ignoring size, face)
|
|
505
|
+
|
|
506
|
+
const base_font = this.fonts[0];
|
|
507
|
+
const font = this.fonts[xf.font || 0];
|
|
508
|
+
|
|
509
|
+
if (font) {
|
|
510
|
+
if (font.bold) props.bold = true;
|
|
511
|
+
if (font.italic) props.italic = true;
|
|
512
|
+
if (font.underline) props.underline = true;
|
|
513
|
+
if (font.strike) props.strike = true;
|
|
514
|
+
|
|
515
|
+
// implement font size... experimental. treat font size as % of
|
|
516
|
+
// base size, which we assume is in slot 0.
|
|
517
|
+
|
|
518
|
+
if (base_font && base_font.size && font.size && base_font.size !== font.size) {
|
|
519
|
+
props.font_size = {
|
|
520
|
+
value: 100 * font.size / base_font.size,
|
|
521
|
+
unit: '%',
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
if (font.color_argb) {
|
|
526
|
+
props.text = {
|
|
527
|
+
text: '#' + (
|
|
528
|
+
font.color_argb.length > 6 ?
|
|
529
|
+
font.color_argb.substr(font.color_argb.length - 6) :
|
|
530
|
+
font.color_argb)
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
else if (typeof font.color_theme === 'number') {
|
|
535
|
+
|
|
536
|
+
// const index = Theme.color_map[];
|
|
537
|
+
|
|
538
|
+
// skipping 0, it's implicit
|
|
539
|
+
// no it is not (1 is implicit?)
|
|
540
|
+
|
|
541
|
+
props.text = { theme: font.color_theme };
|
|
542
|
+
|
|
543
|
+
/*
|
|
544
|
+
// FIXME: update to theme
|
|
545
|
+
console.warn('update to theme colors');
|
|
546
|
+
|
|
547
|
+
const index = Theme.color_map[font.color_theme];
|
|
548
|
+
const color = this.theme.colors[index];
|
|
549
|
+
|
|
550
|
+
// why was I _not_ accepting system here? (...) there's an argument
|
|
551
|
+
// against system 1 -> default...
|
|
552
|
+
|
|
553
|
+
if (color && color.type !== 'system' && color.value) {
|
|
554
|
+
if (typeof font.color_tint === 'number') {
|
|
555
|
+
props.text = '#' + this.TintColor(color.value, font.color_tint);
|
|
556
|
+
}
|
|
557
|
+
else {
|
|
558
|
+
props.text = '#' + color.value;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
else if (color && color.type === 'system' && color.value) {
|
|
563
|
+
|
|
564
|
+
// let's drop color index 1, as that should be default? (...)
|
|
565
|
+
// should do this higher up
|
|
566
|
+
|
|
567
|
+
if (font.color_theme !== 1) {
|
|
568
|
+
props.text = '#' + color.value;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
*/
|
|
572
|
+
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
const fill = this.fills[xf.fill || 0];
|
|
578
|
+
if (fill && fill.pattern_type !== 'none') {
|
|
579
|
+
|
|
580
|
+
if (fill.pattern_type === 'gray') {
|
|
581
|
+
const value = Math.round((fill.pattern_gray || 0) / 1000 * 255);
|
|
582
|
+
// props.background = `rgb(${value}, ${value}, ${value})`;
|
|
583
|
+
props.fill = { text: `rgb(${value}, ${value}, ${value})` };
|
|
584
|
+
}
|
|
585
|
+
if (fill.pattern_type === 'solid') {
|
|
586
|
+
if (fill.fg_color) {
|
|
587
|
+
if (fill.fg_color.argb) {
|
|
588
|
+
props.fill = { text: '#' + (
|
|
589
|
+
fill.fg_color.argb.length > 6 ?
|
|
590
|
+
fill.fg_color.argb.substr(fill.fg_color.argb.length - 6) :
|
|
591
|
+
fill.fg_color.argb)
|
|
592
|
+
};
|
|
593
|
+
}
|
|
594
|
+
else if (typeof fill.fg_color.theme === 'number') {
|
|
595
|
+
|
|
596
|
+
props.fill = {
|
|
597
|
+
theme: fill.fg_color.theme,
|
|
598
|
+
// tint: fill.fg_color.tint,
|
|
599
|
+
};
|
|
600
|
+
|
|
601
|
+
if (fill.fg_color.tint) {
|
|
602
|
+
props.fill.tint = Math.round(fill.fg_color.tint * 1000) / 1000;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/*
|
|
606
|
+
const index = Theme.color_map[fill.fg_color.theme];
|
|
607
|
+
const color = this.theme.colors[index];
|
|
608
|
+
// if (color && color.type !== 'system' && color.value) {
|
|
609
|
+
if (color && color.value) {
|
|
610
|
+
if (typeof fill.fg_color.tint === 'number') {
|
|
611
|
+
props.background = '#' + this.TintColor(color.value, fill.fg_color.tint);
|
|
612
|
+
}
|
|
613
|
+
else {
|
|
614
|
+
props.background = '#' + color.value;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
*/
|
|
618
|
+
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
// alignments (TODO: valign)
|
|
625
|
+
|
|
626
|
+
switch (xf.horizontal_alignment) {
|
|
627
|
+
case 'center':
|
|
628
|
+
props.horizontal_align = Style.HorizontalAlign.Center;
|
|
629
|
+
break;
|
|
630
|
+
case 'right':
|
|
631
|
+
props.horizontal_align = Style.HorizontalAlign.Right;
|
|
632
|
+
break;
|
|
633
|
+
case 'left':
|
|
634
|
+
props.horizontal_align = Style.HorizontalAlign.Left;
|
|
635
|
+
break;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
switch (xf.vertical_alignment) {
|
|
639
|
+
case 'center':
|
|
640
|
+
props.vertical_align = Style.VerticalAlign.Middle;
|
|
641
|
+
break;
|
|
642
|
+
case 'top':
|
|
643
|
+
props.vertical_align = Style.VerticalAlign.Top;
|
|
644
|
+
break;
|
|
645
|
+
case 'bottom':
|
|
646
|
+
props.vertical_align = Style.VerticalAlign.Bottom;
|
|
647
|
+
break;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
// wrap
|
|
651
|
+
|
|
652
|
+
if (xf.wrap_text) {
|
|
653
|
+
props.wrap = true;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
// borders
|
|
657
|
+
|
|
658
|
+
const border = this.borders[xf.border || 0];
|
|
659
|
+
if (border) {
|
|
660
|
+
if (border.bottom.style) {
|
|
661
|
+
if (border.bottom.style === 'double') {
|
|
662
|
+
props.border_bottom = 2;
|
|
663
|
+
}
|
|
664
|
+
else {
|
|
665
|
+
props.border_bottom = 1;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
if (border.left.style) props.border_left = 1;
|
|
669
|
+
if (border.top.style) props.border_top = 1;
|
|
670
|
+
if (border.right.style) props.border_right = 1;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
return props;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
/** map all cell xfs to styles; retain order */
|
|
677
|
+
public CellXfToStyles(): Style.Properties[] {
|
|
678
|
+
return this.cell_xfs.map((xf) => this.CellXfToStyle(xf));
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
|
|
682
|
+
public EnsureNumberFormat(number_format: NumberFormat): number {
|
|
683
|
+
|
|
684
|
+
// there are a lot of default, implicit number formats.
|
|
685
|
+
// we should probably find out what they are. for the time
|
|
686
|
+
// being, just use 0 for no properties.
|
|
687
|
+
|
|
688
|
+
if (typeof number_format.format === 'undefined') return 0;
|
|
689
|
+
|
|
690
|
+
// we changed the casing on this at some point, so let's be
|
|
691
|
+
// broad here. general is important because it has the magic
|
|
692
|
+
// decimal point, we don't want to revert to an explicit style
|
|
693
|
+
// because there's no description syntax for that
|
|
694
|
+
|
|
695
|
+
if (number_format.symbolic_name) {
|
|
696
|
+
if (/^general$/i.test(number_format.symbolic_name)) {
|
|
697
|
+
return 0;
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
// check the rest of the built-in types... note this is not an array?
|
|
702
|
+
// (why not?) also, is the length guaranteed?
|
|
703
|
+
|
|
704
|
+
for (let i = 0; i < 100; i++) {
|
|
705
|
+
const check = StyleCache.default_styles[i];
|
|
706
|
+
if (check && check === number_format.format) {
|
|
707
|
+
return i;
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
for (const candidate of this.number_formats) {
|
|
712
|
+
if (candidate.format === number_format.format) return candidate.id || 0;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
this.modified = true;
|
|
716
|
+
|
|
717
|
+
const new_format = {
|
|
718
|
+
id: this.base_number_format_id++,
|
|
719
|
+
format: number_format.format,
|
|
720
|
+
};
|
|
721
|
+
this.number_formats.push(new_format);
|
|
722
|
+
|
|
723
|
+
/*
|
|
724
|
+
if (!this.dom) throw new Error('missing dom');
|
|
725
|
+
let number_formats = this.dom.find('./numFmts');
|
|
726
|
+
|
|
727
|
+
if (!number_formats){
|
|
728
|
+
number_formats = Element('numFmts', {count: '1'});
|
|
729
|
+
const root = this.dom.getroot();
|
|
730
|
+
(root as any)._children = [number_formats].concat((root as any)._children);
|
|
731
|
+
// this.dom.getroot().append(number_formats);
|
|
732
|
+
}
|
|
733
|
+
else {
|
|
734
|
+
number_formats.attrib.count = (Number(number_formats.attrib.count || 0) + 1).toString();
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
number_formats.append(Element('numFmt', {
|
|
738
|
+
numFmtId: new_format.id.toString(),
|
|
739
|
+
formatCode: new_format.format,
|
|
740
|
+
}));
|
|
741
|
+
*/
|
|
742
|
+
|
|
743
|
+
return new_format.id;
|
|
744
|
+
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
public CompareBorderEdge(a: BorderEdge, b: BorderEdge) {
|
|
748
|
+
return a.color === b.color
|
|
749
|
+
&& a.rgba === b.rgba
|
|
750
|
+
&& a.style === b.style
|
|
751
|
+
&& a.theme === b.theme
|
|
752
|
+
&& a.tint === b.tint;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
public CompareBorder(a: BorderStyle, b: BorderStyle) {
|
|
756
|
+
return this.CompareBorderEdge(a.top, b.top)
|
|
757
|
+
&& this.CompareBorderEdge(a.left, b.left)
|
|
758
|
+
&& this.CompareBorderEdge(a.bottom, b.bottom)
|
|
759
|
+
&& this.CompareBorderEdge(a.right, b.right)
|
|
760
|
+
&& this.CompareBorderEdge(a.diagonal, b.diagonal);
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
public EnsureBorder(border: BorderStyle): number {
|
|
764
|
+
|
|
765
|
+
for (let i = 0; i < this.borders.length; i++ ){
|
|
766
|
+
const candidate = this.borders[i];
|
|
767
|
+
|
|
768
|
+
if (this.CompareBorder(candidate, border)){
|
|
769
|
+
return i;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
this.modified = true;
|
|
775
|
+
|
|
776
|
+
const new_border: BorderStyle = JSON.parse(JSON.stringify(border)); // {...border};
|
|
777
|
+
this.borders.push(new_border);
|
|
778
|
+
|
|
779
|
+
/*
|
|
780
|
+
|
|
781
|
+
if (!this.dom) throw new Error('missing dom');
|
|
782
|
+
const borders = this.dom.find('./borders');
|
|
783
|
+
|
|
784
|
+
if (!borders) throw new Error('borders not found');
|
|
785
|
+
borders.attrib.count = (Number(borders.attrib.count || 0) + 1).toString();
|
|
786
|
+
|
|
787
|
+
const new_element = Element('border');
|
|
788
|
+
|
|
789
|
+
const left = Element('left');
|
|
790
|
+
if (border.left_style) {
|
|
791
|
+
left.attrib.style = border.left_style;
|
|
792
|
+
// left.append(Element('color', {indexed: (border.left_color || 0).toString() }));
|
|
793
|
+
const attrs: ColorAttributes = {};
|
|
794
|
+
if (border.left_color_rgba) {
|
|
795
|
+
attrs.rgb = border.left_color_rgba;
|
|
796
|
+
}
|
|
797
|
+
else if (typeof border.left_color_theme === 'number') {
|
|
798
|
+
attrs.theme = border.left_color_theme.toString();
|
|
799
|
+
if (border.left_color_tint) {
|
|
800
|
+
attrs.tint = border.left_color_tint.toString();
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
else {
|
|
804
|
+
attrs.indexed = (border.left_color || 0).toString();
|
|
805
|
+
}
|
|
806
|
+
left.append(Element('color', attrs as ElementTree.Attributes));
|
|
807
|
+
}
|
|
808
|
+
new_element.append(left);
|
|
809
|
+
|
|
810
|
+
const right = Element('right');
|
|
811
|
+
if (border.right_style) {
|
|
812
|
+
right.attrib.style = border.right_style;
|
|
813
|
+
// right.append(Element('color', {indexed: (border.right_color || 0).toString() }));
|
|
814
|
+
const attrs: ColorAttributes = {};
|
|
815
|
+
if (border.right_color_rgba) {
|
|
816
|
+
attrs.rgb = border.right_color_rgba;
|
|
817
|
+
}
|
|
818
|
+
else if (typeof border.right_color_theme === 'number') {
|
|
819
|
+
attrs.theme = border.right_color_theme.toString();
|
|
820
|
+
if (border.right_color_tint) {
|
|
821
|
+
attrs.tint = border.right_color_tint.toString();
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
else {
|
|
825
|
+
attrs.indexed = (border.right_color || 0).toString();
|
|
826
|
+
}
|
|
827
|
+
right.append(Element('color', attrs as ElementTree.Attributes));
|
|
828
|
+
|
|
829
|
+
}
|
|
830
|
+
new_element.append(right);
|
|
831
|
+
|
|
832
|
+
const top = Element('top');
|
|
833
|
+
if (border.top_style) {
|
|
834
|
+
top.attrib.style = border.top_style;
|
|
835
|
+
const attrs: ColorAttributes = {};
|
|
836
|
+
if (border.top_color_rgba) {
|
|
837
|
+
attrs.rgb = border.top_color_rgba;
|
|
838
|
+
}
|
|
839
|
+
else if (typeof border.top_color_theme === 'number') {
|
|
840
|
+
attrs.theme = border.top_color_theme.toString();
|
|
841
|
+
if (border.top_color_tint) {
|
|
842
|
+
attrs.tint = border.top_color_tint.toString();
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
else {
|
|
846
|
+
attrs.indexed = (border.top_color || 0).toString();
|
|
847
|
+
}
|
|
848
|
+
top.append(Element('color', attrs as ElementTree.Attributes));
|
|
849
|
+
}
|
|
850
|
+
new_element.append(top);
|
|
851
|
+
|
|
852
|
+
const bottom = Element('bottom');
|
|
853
|
+
if (border.bottom_style) {
|
|
854
|
+
|
|
855
|
+
// console.info("BOTTOM STYLE", border);
|
|
856
|
+
|
|
857
|
+
bottom.attrib.style = border.bottom_style;
|
|
858
|
+
// bottom.append(Element('color', {indexed: (border.bottom_color || 0).toString() }));
|
|
859
|
+
const attrs: ColorAttributes = {};
|
|
860
|
+
if (border.bottom_color_rgba) {
|
|
861
|
+
attrs.rgb = border.bottom_color_rgba;
|
|
862
|
+
}
|
|
863
|
+
else if (typeof border.bottom_color_theme === 'number') {
|
|
864
|
+
attrs.theme = border.bottom_color_theme.toString();
|
|
865
|
+
if (border.bottom_color_tint) {
|
|
866
|
+
attrs.tint = border.bottom_color_tint.toString();
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
else {
|
|
870
|
+
attrs.indexed = (border.bottom_color || 0).toString();
|
|
871
|
+
}
|
|
872
|
+
bottom.append(Element('color', attrs as ElementTree.Attributes));
|
|
873
|
+
}
|
|
874
|
+
new_element.append(bottom);
|
|
875
|
+
|
|
876
|
+
const diagonal = Element('diagonal');
|
|
877
|
+
if (border.diagonal_style) {
|
|
878
|
+
diagonal.attrib.style = border.diagonal_style;
|
|
879
|
+
diagonal.append(Element('color', {indexed: (border.diagonal_color || 0).toString() }));
|
|
880
|
+
}
|
|
881
|
+
new_element.append(diagonal);
|
|
882
|
+
|
|
883
|
+
borders.append(new_element);
|
|
884
|
+
*/
|
|
885
|
+
|
|
886
|
+
return this.borders.length - 1;
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
|
|
890
|
+
public MatchColor(a: XlColor|undefined, b: XlColor|undefined): boolean {
|
|
891
|
+
|
|
892
|
+
if (!a && !b) { return true; }
|
|
893
|
+
if (!a || !b) { return false; }
|
|
894
|
+
|
|
895
|
+
return ( a.argb === b.argb
|
|
896
|
+
&& a.indexed === b.indexed
|
|
897
|
+
&& a.theme === b.theme
|
|
898
|
+
&& a.tint === b.tint);
|
|
899
|
+
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
public EnsureFill(fill: Fill): number {
|
|
903
|
+
|
|
904
|
+
for (let i = 0; i < this.fills.length; i++) {
|
|
905
|
+
const candidate = this.fills[i];
|
|
906
|
+
if ( this.MatchColor(fill.bg_color, candidate.bg_color)
|
|
907
|
+
&& this.MatchColor(fill.fg_color, candidate.fg_color)
|
|
908
|
+
&& fill.pattern_gray === candidate.pattern_gray
|
|
909
|
+
&& fill.pattern_type === candidate.pattern_type ) {
|
|
910
|
+
return i;
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
this.modified = true;
|
|
915
|
+
|
|
916
|
+
const new_fill: Fill = {...fill};
|
|
917
|
+
this.fills.push(new_fill);
|
|
918
|
+
|
|
919
|
+
/*
|
|
920
|
+
// add the node structure
|
|
921
|
+
|
|
922
|
+
if (!this.dom) throw new Error('missing dom');
|
|
923
|
+
const fills = this.dom.find('./fills');
|
|
924
|
+
|
|
925
|
+
if (!fills) throw new Error('fills not found');
|
|
926
|
+
fills.attrib.count = (Number(fills.attrib.count || 0) + 1).toString();
|
|
927
|
+
|
|
928
|
+
const new_element = Element('fill');
|
|
929
|
+
const pattern_fill = Element('patternFill', { patternType: fill.pattern_type });
|
|
930
|
+
|
|
931
|
+
switch (fill.pattern_type) {
|
|
932
|
+
case 'none':
|
|
933
|
+
break;
|
|
934
|
+
case 'solid':
|
|
935
|
+
if (fill.fg_color) {
|
|
936
|
+
const attrs: Record<string, string> = {};
|
|
937
|
+
|
|
938
|
+
if (fill.fg_color.argb) { attrs.rgb = fill.fg_color.argb; }
|
|
939
|
+
if (fill.fg_color.indexed) { attrs.indexed = fill.fg_color.indexed.toString(); }
|
|
940
|
+
if (fill.fg_color.tint) { attrs.tint = fill.fg_color.tint.toString(); }
|
|
941
|
+
if (typeof fill.fg_color.theme !== 'undefined') { attrs.theme = fill.fg_color.theme.toString(); }
|
|
942
|
+
|
|
943
|
+
pattern_fill.append(Element('fgColor', attrs));
|
|
944
|
+
}
|
|
945
|
+
break;
|
|
946
|
+
case 'gray':
|
|
947
|
+
|
|
948
|
+
// ...
|
|
949
|
+
|
|
950
|
+
break;
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
new_element.append(pattern_fill);
|
|
954
|
+
|
|
955
|
+
fills.append(new_element);
|
|
956
|
+
*/
|
|
957
|
+
|
|
958
|
+
return this.fills.length - 1;
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
/**
|
|
962
|
+
* for the time being we are ignoring font face, family, size, color and
|
|
963
|
+
* scheme (whatever that is). every font is based on font 0, the default.
|
|
964
|
+
* we add bold/italic/underline as necessary.
|
|
965
|
+
*/
|
|
966
|
+
public EnsureFont(font: Font): number {
|
|
967
|
+
|
|
968
|
+
// this is what we create, so we need to test against it
|
|
969
|
+
|
|
970
|
+
const composite_font: Font = {...this.fonts[0], ...font};
|
|
971
|
+
|
|
972
|
+
// const props = Object.keys(font).filter((key) => typeof (font as any)[key] !== 'undefined');
|
|
973
|
+
for (let i = 0; i < this.fonts.length; i++ ){
|
|
974
|
+
const candidate = this.fonts[i];
|
|
975
|
+
//let match = true;
|
|
976
|
+
//for (const prop of props) {
|
|
977
|
+
// match = match && (font as any)[prop] === (candidate as any)[prop];
|
|
978
|
+
//}
|
|
979
|
+
|
|
980
|
+
const match = (candidate.bold === composite_font.bold)
|
|
981
|
+
&& (candidate.italic === composite_font.italic)
|
|
982
|
+
&& (candidate.underline === composite_font.underline)
|
|
983
|
+
&& (candidate.size === composite_font.size)
|
|
984
|
+
&& (candidate.strike === composite_font.strike)
|
|
985
|
+
&& (candidate.color_argb === composite_font.color_argb)
|
|
986
|
+
&& (candidate.color_theme === composite_font.color_theme)
|
|
987
|
+
&& (candidate.color_tint === composite_font.color_tint)
|
|
988
|
+
&& (candidate.family === composite_font.family);
|
|
989
|
+
|
|
990
|
+
if (match) {
|
|
991
|
+
return i;
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
this.modified = true;
|
|
997
|
+
|
|
998
|
+
// const composite_font = test; // {...this.fonts[0], ...font};
|
|
999
|
+
this.fonts.push(composite_font);
|
|
1000
|
+
|
|
1001
|
+
/*
|
|
1002
|
+
// add the node structure
|
|
1003
|
+
|
|
1004
|
+
if (!this.dom) throw new Error('missing dom');
|
|
1005
|
+
const fonts = this.dom.find('./fonts');
|
|
1006
|
+
|
|
1007
|
+
if (!fonts) throw new Error('fonts not found');
|
|
1008
|
+
fonts.attrib.count = (Number(fonts.attrib.count || 0) + 1).toString();
|
|
1009
|
+
|
|
1010
|
+
const new_element = Element('font');
|
|
1011
|
+
new_element.append(Element('sz', { val: (composite_font.size || 0).toString() }));
|
|
1012
|
+
|
|
1013
|
+
// new_element.append(Element('color', { theme: (new_font.color_theme || 0).toString() }));
|
|
1014
|
+
// new_element.append(Element('color', { theme: (new_font.color_theme || 0).toString() }));
|
|
1015
|
+
|
|
1016
|
+
if (typeof composite_font.color_argb !== 'undefined') {
|
|
1017
|
+
new_element.append(Element('color', { rgb: composite_font.color_argb }));
|
|
1018
|
+
}
|
|
1019
|
+
else {
|
|
1020
|
+
new_element.append(Element('color', { theme: (composite_font.color_theme || 0).toString() }));
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
new_element.append(Element('name', { val: composite_font.name }));
|
|
1024
|
+
new_element.append(Element('family', { val: (composite_font.family || 0).toString() }));
|
|
1025
|
+
new_element.append(Element('scheme', { val: composite_font.scheme }));
|
|
1026
|
+
|
|
1027
|
+
if (composite_font.bold) new_element.append(Element('b'));
|
|
1028
|
+
if (composite_font.underline) new_element.append(Element('u'));
|
|
1029
|
+
if (composite_font.italic) new_element.append(Element('i'));
|
|
1030
|
+
if (composite_font.strike) new_element.append(Element('strike'));
|
|
1031
|
+
|
|
1032
|
+
fonts.append(new_element);
|
|
1033
|
+
*/
|
|
1034
|
+
|
|
1035
|
+
return this.fonts.length - 1;
|
|
1036
|
+
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
public EnsureStyle(options: StyleOptions): number {
|
|
1040
|
+
|
|
1041
|
+
// find indexes for props
|
|
1042
|
+
const font_index = this.EnsureFont(options.font || {});
|
|
1043
|
+
const border_index = this.EnsureBorder(options.border || default_border);
|
|
1044
|
+
const number_format_index = this.EnsureNumberFormat(options.number_format || {});
|
|
1045
|
+
const fill_index = this.EnsureFill(options.fill || { pattern_type: 'none' });
|
|
1046
|
+
|
|
1047
|
+
// now find an XF that matches
|
|
1048
|
+
for (let i = 0; i < this.cell_xfs.length; i++){
|
|
1049
|
+
const xf = this.cell_xfs[i];
|
|
1050
|
+
if (xf.font === font_index &&
|
|
1051
|
+
xf.fill === fill_index &&
|
|
1052
|
+
xf.border === border_index &&
|
|
1053
|
+
xf.number_format === number_format_index &&
|
|
1054
|
+
!!xf.wrap_text === !!options.wrap &&
|
|
1055
|
+
((!options.horizontal_alignment && !xf.horizontal_alignment) || options.horizontal_alignment === xf.horizontal_alignment) &&
|
|
1056
|
+
((!options.vertical_alignment && !xf.vertical_alignment) || options.vertical_alignment === xf.vertical_alignment)) {
|
|
1057
|
+
|
|
1058
|
+
return i;
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
this.modified = true;
|
|
1063
|
+
|
|
1064
|
+
// need a new XF -- defaults?
|
|
1065
|
+
const new_xf: CellXf = {
|
|
1066
|
+
font: font_index,
|
|
1067
|
+
fill: fill_index,
|
|
1068
|
+
border: border_index,
|
|
1069
|
+
number_format: number_format_index,
|
|
1070
|
+
};
|
|
1071
|
+
|
|
1072
|
+
if (options.horizontal_alignment) {
|
|
1073
|
+
new_xf.horizontal_alignment = options.horizontal_alignment;
|
|
1074
|
+
}
|
|
1075
|
+
if (options.vertical_alignment) {
|
|
1076
|
+
new_xf.vertical_alignment = options.vertical_alignment;
|
|
1077
|
+
}
|
|
1078
|
+
if (options.wrap) {
|
|
1079
|
+
new_xf.wrap_text = true;
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
this.cell_xfs.push(new_xf);
|
|
1083
|
+
|
|
1084
|
+
/*
|
|
1085
|
+
|
|
1086
|
+
// add the node structure
|
|
1087
|
+
|
|
1088
|
+
if (!this.dom) throw new Error('missing dom');
|
|
1089
|
+
const xfs = this.dom.find('./cellXfs');
|
|
1090
|
+
|
|
1091
|
+
if (!xfs) throw new Error('xfs not found');
|
|
1092
|
+
xfs.attrib.count = (Number(xfs.attrib.count || 0) + 1).toString();
|
|
1093
|
+
|
|
1094
|
+
const new_element = Element('xf', {
|
|
1095
|
+
borderId: new_xf.border.toString(),
|
|
1096
|
+
fillId: new_xf.fill.toString(),
|
|
1097
|
+
fontId: new_xf.font.toString(),
|
|
1098
|
+
numFmtId: new_xf.number_format.toString(),
|
|
1099
|
+
});
|
|
1100
|
+
|
|
1101
|
+
if (new_xf.horizontal_alignment || new_xf.vertical_alignment) {
|
|
1102
|
+
const attrs: {[index: string]: string} = {};
|
|
1103
|
+
if (new_xf.horizontal_alignment) {
|
|
1104
|
+
attrs.horizontal = new_xf.horizontal_alignment;
|
|
1105
|
+
}
|
|
1106
|
+
if (new_xf.vertical_alignment) {
|
|
1107
|
+
attrs.vertical = new_xf.vertical_alignment;
|
|
1108
|
+
}
|
|
1109
|
+
if (new_xf.wrap_text) {
|
|
1110
|
+
attrs.wrapText = '1';
|
|
1111
|
+
}
|
|
1112
|
+
new_element.append(Element('alignment', attrs));
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
if (typeof new_xf.xfid !== 'undefined') {
|
|
1116
|
+
new_element.attrib.xfId = new_xf.xfid.toString();
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
xfs.append(new_element);
|
|
1120
|
+
*/
|
|
1121
|
+
|
|
1122
|
+
return this.cell_xfs.length - 1;
|
|
1123
|
+
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
public FromXML(xml: any, theme: Theme): void {
|
|
1127
|
+
|
|
1128
|
+
const FindAll = XMLUtils.FindAll.bind(XMLUtils, xml);
|
|
1129
|
+
|
|
1130
|
+
this.theme = theme;
|
|
1131
|
+
|
|
1132
|
+
// ---
|
|
1133
|
+
|
|
1134
|
+
let composite = FindAll('styleSheet/numFmts/numFmt');
|
|
1135
|
+
|
|
1136
|
+
this.number_formats = composite.map(element => ({
|
|
1137
|
+
id: Number(element.a$?.numFmtId || 0),
|
|
1138
|
+
format: Unescape(element.a$?.formatCode || ''),
|
|
1139
|
+
}));
|
|
1140
|
+
|
|
1141
|
+
// ---
|
|
1142
|
+
|
|
1143
|
+
composite = FindAll('styleSheet/borders/border');
|
|
1144
|
+
|
|
1145
|
+
this.borders = composite.map(element => {
|
|
1146
|
+
|
|
1147
|
+
const border: BorderStyle = JSON.parse(JSON.stringify(default_border));
|
|
1148
|
+
|
|
1149
|
+
// we're relying on these being empty strings -> falsy, not a good look
|
|
1150
|
+
|
|
1151
|
+
if (element.left) {
|
|
1152
|
+
border.left.style = element.left.a$.style;
|
|
1153
|
+
border.left.color = Number(element.left.color?.a$?.indexed);
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
if (element.right) {
|
|
1157
|
+
border.right.style = element.right.a$.style;
|
|
1158
|
+
border.right.color = Number(element.right.color?.a$?.indexed);
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
if (element.top) {
|
|
1162
|
+
border.top.style = element.top.a$.style;
|
|
1163
|
+
border.top.color = Number(element.top.color?.a$?.indexed);
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
if (element.bottom) {
|
|
1167
|
+
border.bottom.style = element.bottom.a$.style;
|
|
1168
|
+
border.bottom.color = Number(element.bottom.color?.a$?.indexed);
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
return border;
|
|
1172
|
+
|
|
1173
|
+
});
|
|
1174
|
+
|
|
1175
|
+
// ---
|
|
1176
|
+
|
|
1177
|
+
composite = FindAll('styleSheet/cellXfs/xf');
|
|
1178
|
+
this.cell_xfs = composite.map(element => {
|
|
1179
|
+
|
|
1180
|
+
const xf: CellXf = {
|
|
1181
|
+
number_format: Number(element.a$.numFmtId),
|
|
1182
|
+
font: Number(element.a$.fontId),
|
|
1183
|
+
fill: Number(element.a$.fillId),
|
|
1184
|
+
border: Number(element.a$.borderId),
|
|
1185
|
+
xfid: Number(element.a$.xfId),
|
|
1186
|
+
};
|
|
1187
|
+
|
|
1188
|
+
if (element.alignment) {
|
|
1189
|
+
xf.horizontal_alignment = element.alignment.a$.horizontal;
|
|
1190
|
+
xf.vertical_alignment = element.alignment.a$.vertical;
|
|
1191
|
+
xf.wrap_text = !!element.alignment.a$.wrapText;
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
return xf;
|
|
1195
|
+
|
|
1196
|
+
});
|
|
1197
|
+
|
|
1198
|
+
// ---
|
|
1199
|
+
|
|
1200
|
+
composite = FindAll('styleSheet/fills/fill');
|
|
1201
|
+
|
|
1202
|
+
this.fills = composite.map(element => {
|
|
1203
|
+
|
|
1204
|
+
const fill: Fill = { pattern_type: 'none' };
|
|
1205
|
+
if (element.patternFill) {
|
|
1206
|
+
const type = element.patternFill.a$?.patternType;
|
|
1207
|
+
switch (type) {
|
|
1208
|
+
case 'none':
|
|
1209
|
+
case undefined:
|
|
1210
|
+
break;
|
|
1211
|
+
|
|
1212
|
+
case 'solid':
|
|
1213
|
+
fill.pattern_type = 'solid';
|
|
1214
|
+
if (element.patternFill.fgColor) {
|
|
1215
|
+
fill.fg_color = {
|
|
1216
|
+
theme: element.patternFill.fgColor.a$?.theme ? Number(element.patternFill.fgColor.a$.theme) : undefined,
|
|
1217
|
+
indexed: element.patternFill.fgColor.a$?.indexed ? Number(element.patternFill.fgColor.a$.indexed) : undefined,
|
|
1218
|
+
tint: element.patternFill.fgColor.a$?.tint ? Number(element.patternFill.fgColor.a$.tint) : undefined,
|
|
1219
|
+
argb: element.patternFill.fgColor.a$?.rgb,
|
|
1220
|
+
};
|
|
1221
|
+
}
|
|
1222
|
+
break;
|
|
1223
|
+
|
|
1224
|
+
default:
|
|
1225
|
+
{
|
|
1226
|
+
const match = type?.match(/^gray(\d+)$/);
|
|
1227
|
+
if (match) {
|
|
1228
|
+
fill.pattern_type = 'gray';
|
|
1229
|
+
fill.pattern_gray = Number(match[1]);
|
|
1230
|
+
break;
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
return fill;
|
|
1238
|
+
|
|
1239
|
+
});
|
|
1240
|
+
|
|
1241
|
+
// ---
|
|
1242
|
+
|
|
1243
|
+
composite = FindAll('styleSheet/fonts/font');
|
|
1244
|
+
|
|
1245
|
+
this.fonts = composite.map(element => {
|
|
1246
|
+
|
|
1247
|
+
const font: Font = {};
|
|
1248
|
+
|
|
1249
|
+
font.italic = !!(typeof element.i !== 'undefined');
|
|
1250
|
+
font.bold = !!(typeof element.b !== 'undefined');
|
|
1251
|
+
font.underline = !!(typeof element.u !== 'undefined');
|
|
1252
|
+
font.strike = !!(typeof element.strike !== 'undefined');
|
|
1253
|
+
|
|
1254
|
+
if (element.sz) {
|
|
1255
|
+
font.size = Number(element.sz.a$.val);
|
|
1256
|
+
}
|
|
1257
|
+
if (element.scheme) {
|
|
1258
|
+
font.scheme = element.scheme.a$.val;
|
|
1259
|
+
}
|
|
1260
|
+
if (element.name) {
|
|
1261
|
+
font.name = element.name.a$.val;
|
|
1262
|
+
}
|
|
1263
|
+
if (element.family) {
|
|
1264
|
+
font.family = Number(element.family.a$.val);
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
if (element.color) {
|
|
1268
|
+
if (element.color.a$?.theme) {
|
|
1269
|
+
font.color_theme = Number(element.color.a$.theme);
|
|
1270
|
+
}
|
|
1271
|
+
if (element.color.a$?.tint) {
|
|
1272
|
+
font.color_tint = Number(element.color.a$.tint);
|
|
1273
|
+
}
|
|
1274
|
+
if (element.color.a$?.rgb) {
|
|
1275
|
+
font.color_argb = element.color.a$.rgb;
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
return font;
|
|
1280
|
+
|
|
1281
|
+
});
|
|
1282
|
+
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
}
|