@trebco/treb 27.12.2 → 28.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 +6 -0
- package/dist/treb-spreadsheet-light.mjs +16 -0
- package/dist/treb-spreadsheet.mjs +13 -11
- package/dist/treb.d.ts +33 -5
- package/esbuild-custom-element.mjs +3 -1
- package/package.json +8 -6
- package/treb-base-types/src/dom-utilities.ts +157 -19
- package/treb-base-types/src/import.ts +1 -0
- package/treb-base-types/src/theme.ts +5 -4
- package/treb-charts/src/renderer.ts +4 -58
- package/treb-embed/markup/layout.html +4 -0
- package/treb-embed/src/custom-element/spreadsheet-constructor.ts +131 -87
- package/treb-embed/src/embedded-spreadsheet.ts +153 -140
- package/treb-embed/src/options.ts +9 -0
- package/treb-embed/src/spinner.ts +5 -3
- package/treb-embed/src/toolbar-message.ts +5 -0
- package/treb-embed/style/layout.scss +65 -1
- package/treb-export/src/export-worker/export-worker.ts +7 -12
- package/treb-export/src/export2.ts +57 -33
- package/treb-export/src/import2.ts +61 -21
- package/treb-export/src/workbook2.ts +69 -24
- package/treb-export/src/zip-wrapper.ts +96 -0
- package/treb-grid/src/editors/autocomplete.ts +24 -13
- package/treb-grid/src/editors/editor.ts +43 -139
- package/treb-grid/src/editors/external_editor.ts +1 -1
- package/treb-grid/src/editors/formula_bar.ts +24 -24
- package/treb-grid/src/editors/overlay_editor.ts +1 -1
- package/treb-grid/src/layout/base_layout.ts +34 -25
- package/treb-grid/src/layout/grid_layout.ts +20 -20
- package/treb-grid/src/render/selection-renderer.ts +3 -3
- package/treb-grid/src/render/svg_header_overlay.ts +6 -4
- package/treb-grid/src/render/svg_selection_block.ts +10 -7
- package/treb-grid/src/types/annotation.ts +2 -2
- package/treb-grid/src/types/grid.ts +80 -81
- package/treb-grid/src/types/scale-control.ts +69 -81
- package/treb-grid/src/types/sheet.ts +3 -52
- package/treb-grid/src/types/tab_bar.ts +27 -13
- package/treb-grid/src/util/fontmetrics2.ts +24 -21
- package/treb-utils/src/event_source.ts +23 -23
- package/treb-utils/src/index.ts +2 -2
- package/treb-utils/src/measurement.ts +24 -24
- package/treb-utils/src/serialize_html.ts +25 -21
- package/treb-utils/src/dispatch.ts +0 -57
- package/treb-utils/src/resizable.ts +0 -159
|
@@ -25,7 +25,10 @@
|
|
|
25
25
|
* run, but it will take a bit more work.
|
|
26
26
|
*/
|
|
27
27
|
|
|
28
|
-
import JSZip from 'jszip';
|
|
28
|
+
// import JSZip from 'jszip';
|
|
29
|
+
|
|
30
|
+
import UZip from 'uzip';
|
|
31
|
+
import * as Base64JS from 'base64-js';
|
|
29
32
|
|
|
30
33
|
import { PixelsToColumnWidth } from './column-width';
|
|
31
34
|
|
|
@@ -62,10 +65,12 @@ import type { TwoCellAnchor } from './drawing2/drawing2';
|
|
|
62
65
|
import { Drawing } from './drawing2/drawing2';
|
|
63
66
|
import { ConditionalFormatOperators, type TableDescription, type TableFooterType } from './workbook2';
|
|
64
67
|
import type { AnnotationData } from 'treb-grid/src/types/annotation';
|
|
68
|
+
import { ZipWrapper } from './zip-wrapper';
|
|
65
69
|
|
|
66
70
|
export class Exporter {
|
|
67
71
|
|
|
68
|
-
public zip?: JSZip;
|
|
72
|
+
// public zip?: JSZip;
|
|
73
|
+
public zip?: ZipWrapper;
|
|
69
74
|
|
|
70
75
|
public xmloptions: Partial<XmlBuilderOptions> = {
|
|
71
76
|
format: true,
|
|
@@ -129,19 +134,18 @@ export class Exporter {
|
|
|
129
134
|
*
|
|
130
135
|
* @param decorated_functions
|
|
131
136
|
*/
|
|
132
|
-
public
|
|
133
|
-
|
|
134
|
-
// this.decorated_functions = decorated_functions.map(name => name.toLowerCase()); // normalized
|
|
137
|
+
public Init(decorated_functions: Record<string, string> = {}) {
|
|
135
138
|
|
|
136
139
|
for (const key of Object.keys(decorated_functions)) {
|
|
137
140
|
this.decorated_functions[key.toLowerCase()] = decorated_functions[key]; // normalized
|
|
138
141
|
}
|
|
139
142
|
|
|
140
|
-
|
|
143
|
+
const parsed = Base64JS.toByteArray(template);
|
|
144
|
+
this.zip = new ZipWrapper(parsed);
|
|
141
145
|
|
|
142
146
|
}
|
|
143
147
|
|
|
144
|
-
public
|
|
148
|
+
public WriteRels(rels: RelationshipMap, path: string, dump = false) {
|
|
145
149
|
|
|
146
150
|
if (!this.zip) {
|
|
147
151
|
throw new Error('missing zip');
|
|
@@ -176,14 +180,15 @@ export class Exporter {
|
|
|
176
180
|
if (dump) {
|
|
177
181
|
console.info(xml);
|
|
178
182
|
}
|
|
179
|
-
|
|
183
|
+
|
|
184
|
+
this.zip.Set(path, xml);
|
|
180
185
|
|
|
181
186
|
}
|
|
182
187
|
|
|
183
188
|
/**
|
|
184
189
|
* format and write styles
|
|
185
190
|
*/
|
|
186
|
-
public
|
|
191
|
+
public WriteStyleCache(style_cache: StyleCache) {
|
|
187
192
|
|
|
188
193
|
if (!this.zip) {
|
|
189
194
|
throw new Error('missing zip');
|
|
@@ -501,7 +506,7 @@ export class Exporter {
|
|
|
501
506
|
const xml = XMLDeclaration + this.xmlbuilder1.build(dom);
|
|
502
507
|
// console.info(xml);
|
|
503
508
|
|
|
504
|
-
|
|
509
|
+
this.zip?.Set('xl/styles.xml', xml);
|
|
505
510
|
|
|
506
511
|
}
|
|
507
512
|
|
|
@@ -509,7 +514,7 @@ export class Exporter {
|
|
|
509
514
|
* format and write shared strings file to the zip archive. this will
|
|
510
515
|
* replace any existing shared strings file.
|
|
511
516
|
*/
|
|
512
|
-
public
|
|
517
|
+
public WriteSharedStrings(shared_strings: SharedStrings) {
|
|
513
518
|
|
|
514
519
|
// console.info({shared_strings});
|
|
515
520
|
|
|
@@ -534,7 +539,7 @@ export class Exporter {
|
|
|
534
539
|
|
|
535
540
|
// console.info(xml);
|
|
536
541
|
|
|
537
|
-
|
|
542
|
+
this.zip.Set('xl/sharedStrings.xml', xml);
|
|
538
543
|
|
|
539
544
|
}
|
|
540
545
|
|
|
@@ -1157,13 +1162,13 @@ export class Exporter {
|
|
|
1157
1162
|
|
|
1158
1163
|
}
|
|
1159
1164
|
|
|
1160
|
-
public
|
|
1165
|
+
public Export(source: {
|
|
1161
1166
|
sheet_data: SerializedSheet[];
|
|
1162
1167
|
active_sheet?: number;
|
|
1163
1168
|
named_ranges?: {[index: string]: IArea};
|
|
1164
1169
|
named_expressions?: Array<{ name: string, expression: string }>;
|
|
1165
1170
|
decimal_mark: ','|'.';
|
|
1166
|
-
})
|
|
1171
|
+
}) {
|
|
1167
1172
|
|
|
1168
1173
|
// --- create a map --------------------------------------------------------
|
|
1169
1174
|
|
|
@@ -1198,11 +1203,11 @@ export class Exporter {
|
|
|
1198
1203
|
const style_cache = new StyleCache();
|
|
1199
1204
|
const theme = new Theme();
|
|
1200
1205
|
|
|
1201
|
-
let data =
|
|
1206
|
+
let data = this.zip?.Get('xl/theme/theme1.xml');
|
|
1202
1207
|
theme.FromXML(this.xmlparser2.parse(data || ''));
|
|
1203
1208
|
// console.info({data, xml: this.xmlparser2.parse(data)})
|
|
1204
1209
|
|
|
1205
|
-
data =
|
|
1210
|
+
data = this.zip?.Get('xl/styles.xml');
|
|
1206
1211
|
style_cache.FromXML(this.xmlparser2.parse(data || ''), theme);
|
|
1207
1212
|
|
|
1208
1213
|
// reset counters
|
|
@@ -2037,7 +2042,7 @@ export class Exporter {
|
|
|
2037
2042
|
};
|
|
2038
2043
|
|
|
2039
2044
|
const xml = XMLDeclaration + this.xmlbuilder1.build(table_dom);
|
|
2040
|
-
|
|
2045
|
+
this.zip?.Set(`xl/tables/table${table.index}.xml`, xml);
|
|
2041
2046
|
|
|
2042
2047
|
}
|
|
2043
2048
|
|
|
@@ -2304,25 +2309,27 @@ export class Exporter {
|
|
|
2304
2309
|
}
|
|
2305
2310
|
|
|
2306
2311
|
for (const {image} of drawing.images) {
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2312
|
+
if (image.options.data) {
|
|
2313
|
+
this.zip?.SetBinary(
|
|
2314
|
+
`xl/media/image${image.index}.${image.extension}`,
|
|
2315
|
+
image.options.data,
|
|
2316
|
+
image.options.encoding);
|
|
2317
|
+
}
|
|
2311
2318
|
// no media rels!
|
|
2312
2319
|
}
|
|
2313
2320
|
|
|
2314
2321
|
for (const {chart} of drawing.charts) {
|
|
2315
2322
|
const dom = chart.toJSON();
|
|
2316
2323
|
const xml = XMLDeclaration + this.xmlbuilder1.build(dom);
|
|
2317
|
-
|
|
2318
|
-
|
|
2324
|
+
this.zip?.Set(`xl/charts/chart${chart.index}.xml`, xml);
|
|
2325
|
+
this.WriteRels(chart.relationships, `xl/charts/_rels/chart${chart.index}.xml.rels`);
|
|
2319
2326
|
}
|
|
2320
2327
|
|
|
2321
|
-
|
|
2328
|
+
this.WriteRels(drawing.relationships, `xl/drawings/_rels/drawing${drawing.index}.xml.rels`);
|
|
2322
2329
|
|
|
2323
2330
|
const xml = XMLDeclaration + this.xmlbuilder1.build(drawing.toJSON());
|
|
2324
2331
|
|
|
2325
|
-
|
|
2332
|
+
this.zip?.Set(`xl/drawings/drawing${drawing.index}.xml`, xml);
|
|
2326
2333
|
|
|
2327
2334
|
drawings.push(drawing); // for [ContentTypes]
|
|
2328
2335
|
|
|
@@ -2358,7 +2365,7 @@ export class Exporter {
|
|
|
2358
2365
|
|
|
2359
2366
|
// write this into the file
|
|
2360
2367
|
|
|
2361
|
-
|
|
2368
|
+
this.zip?.Set(`xl/worksheets/sheet${sheet_index + 1}.xml`, xml);
|
|
2362
2369
|
if (Object.keys(sheet_rels).length) {
|
|
2363
2370
|
this.WriteRels(sheet_rels, `xl/worksheets/_rels/sheet${sheet_index + 1}.xml.rels`);
|
|
2364
2371
|
}
|
|
@@ -2369,8 +2376,8 @@ export class Exporter {
|
|
|
2369
2376
|
|
|
2370
2377
|
// these are workbook global so after all sheets are done
|
|
2371
2378
|
|
|
2372
|
-
|
|
2373
|
-
|
|
2379
|
+
this.WriteSharedStrings(shared_strings);
|
|
2380
|
+
this.WriteStyleCache(style_cache);
|
|
2374
2381
|
|
|
2375
2382
|
// now have to write/update
|
|
2376
2383
|
//
|
|
@@ -2389,7 +2396,7 @@ export class Exporter {
|
|
|
2389
2396
|
`worksheets/sheet${index + 1}.xml`,
|
|
2390
2397
|
));
|
|
2391
2398
|
|
|
2392
|
-
|
|
2399
|
+
this.WriteRels(workbook_rels, `xl/_rels/workbook.xml.rels`);
|
|
2393
2400
|
|
|
2394
2401
|
let definedNames: any = {definedName: []};
|
|
2395
2402
|
if (source.named_ranges) {
|
|
@@ -2480,7 +2487,7 @@ export class Exporter {
|
|
|
2480
2487
|
|
|
2481
2488
|
const workbook_xml = XMLDeclaration + this.xmlbuilder1.build(workbook_dom);
|
|
2482
2489
|
// console.info(workbook_xml);
|
|
2483
|
-
|
|
2490
|
+
this.zip?.Set(`xl/workbook.xml`, workbook_xml);
|
|
2484
2491
|
|
|
2485
2492
|
// const extensions: Array<{ Extension: string, ContentType: string }> = [];
|
|
2486
2493
|
const extensions: Record<string, string> = {};
|
|
@@ -2560,11 +2567,26 @@ export class Exporter {
|
|
|
2560
2567
|
|
|
2561
2568
|
const content_types_xml = XMLDeclaration + this.xmlbuilder1.build(content_types_dom);
|
|
2562
2569
|
// console.info(content_types_xml);
|
|
2563
|
-
|
|
2570
|
+
this.zip?.Set(`[Content_Types].xml`, content_types_xml);
|
|
2564
2571
|
|
|
2565
2572
|
}
|
|
2566
2573
|
|
|
2567
|
-
|
|
2574
|
+
public ArrayBuffer() {
|
|
2575
|
+
if (!this.zip) {
|
|
2576
|
+
throw new Error('missing zip');
|
|
2577
|
+
}
|
|
2578
|
+
return this.zip.ArrayBuffer();
|
|
2579
|
+
}
|
|
2580
|
+
|
|
2581
|
+
public Blob() {
|
|
2582
|
+
if (!this.zip) {
|
|
2583
|
+
throw new Error('missing zip');
|
|
2584
|
+
}
|
|
2585
|
+
const buffer = this.zip.ArrayBuffer();
|
|
2586
|
+
return new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
|
|
2587
|
+
}
|
|
2588
|
+
|
|
2589
|
+
/* * zip -> binary string * /
|
|
2568
2590
|
public async AsBinaryString(compression_level?: number) {
|
|
2569
2591
|
if (!this.zip) {
|
|
2570
2592
|
throw new Error('missing zip');
|
|
@@ -2578,7 +2600,7 @@ export class Exporter {
|
|
|
2578
2600
|
return output;
|
|
2579
2601
|
}
|
|
2580
2602
|
|
|
2581
|
-
|
|
2603
|
+
/* * zip -> blob * /
|
|
2582
2604
|
public async AsBlob(compression_level?: number) {
|
|
2583
2605
|
if (!this.zip) {
|
|
2584
2606
|
throw new Error('missing zip');
|
|
@@ -2591,5 +2613,7 @@ export class Exporter {
|
|
|
2591
2613
|
const output = await this.zip.generateAsync(opts);
|
|
2592
2614
|
return output;
|
|
2593
2615
|
}
|
|
2616
|
+
*/
|
|
2617
|
+
|
|
2594
2618
|
|
|
2595
2619
|
}
|
|
@@ -19,10 +19,12 @@
|
|
|
19
19
|
*
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
//import
|
|
23
|
-
import JSZip from 'jszip';
|
|
22
|
+
// import JSZip from 'jszip';
|
|
24
23
|
|
|
25
|
-
import
|
|
24
|
+
import UZip from 'uzip';
|
|
25
|
+
import Base64JS from 'base64-js';
|
|
26
|
+
|
|
27
|
+
import type { AnchoredChartDescription, AnchoredImageDescription} from './workbook2';
|
|
26
28
|
import { ChartType, ConditionalFormatOperators, Workbook } from './workbook2';
|
|
27
29
|
import type { ParseResult } from 'treb-parser';
|
|
28
30
|
import { Parser } from 'treb-parser';
|
|
@@ -38,6 +40,7 @@ import { XMLUtils } from './xml-utils';
|
|
|
38
40
|
// import { one_hundred_pixels } from './constants';
|
|
39
41
|
import { ColumnWidthToPixels } from './column-width';
|
|
40
42
|
import type { AnnotationType, ConditionalFormat } from 'treb-grid';
|
|
43
|
+
import { ZipWrapper } from './zip-wrapper';
|
|
41
44
|
|
|
42
45
|
interface SharedFormula {
|
|
43
46
|
row: number;
|
|
@@ -55,22 +58,14 @@ export class Importer {
|
|
|
55
58
|
|
|
56
59
|
public workbook?: Workbook;
|
|
57
60
|
|
|
58
|
-
public archive?: JSZip;
|
|
59
|
-
|
|
60
|
-
public async Init(data: string | JSZip): Promise<void> {
|
|
61
|
+
// public archive?: JSZip;
|
|
61
62
|
|
|
62
|
-
|
|
63
|
-
this.archive = await JSZip().loadAsync(data);
|
|
64
|
-
}
|
|
65
|
-
else {
|
|
66
|
-
this.archive = data;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (this.archive) {
|
|
70
|
-
this.workbook = new Workbook(this.archive);
|
|
71
|
-
await this.workbook.Init();
|
|
72
|
-
}
|
|
63
|
+
public zip?: ZipWrapper;
|
|
73
64
|
|
|
65
|
+
public Init(data: ArrayBuffer) {
|
|
66
|
+
this.zip = new ZipWrapper(data);
|
|
67
|
+
this.workbook = new Workbook(this.zip);
|
|
68
|
+
this.workbook.Init();
|
|
74
69
|
}
|
|
75
70
|
|
|
76
71
|
/** FIXME: accessor */
|
|
@@ -465,7 +460,7 @@ export class Importer {
|
|
|
465
460
|
return undefined;
|
|
466
461
|
}
|
|
467
462
|
|
|
468
|
-
public
|
|
463
|
+
public GetSheet(index = 0): ImportedSheetData {
|
|
469
464
|
|
|
470
465
|
if (!this.workbook) {
|
|
471
466
|
throw new Error('missing workbook');
|
|
@@ -764,7 +759,7 @@ export class Importer {
|
|
|
764
759
|
const relationship = sheet.rels[rel];
|
|
765
760
|
if (relationship) {
|
|
766
761
|
reference = relationship.target || '';
|
|
767
|
-
const description =
|
|
762
|
+
const description = this.workbook.ReadTable(reference);
|
|
768
763
|
if (description) {
|
|
769
764
|
|
|
770
765
|
// console.info({description});
|
|
@@ -806,8 +801,10 @@ export class Importer {
|
|
|
806
801
|
|
|
807
802
|
const drawings = FindAll('worksheet/drawing');
|
|
808
803
|
const chart_descriptors: AnchoredChartDescription[] = [];
|
|
804
|
+
const image_descriptors: AnchoredImageDescription[] = [];
|
|
809
805
|
|
|
810
806
|
for (const child of drawings) {
|
|
807
|
+
|
|
811
808
|
const rel = child.a$ ? child.a$['r:id'] : undefined;
|
|
812
809
|
if (rel) {
|
|
813
810
|
|
|
@@ -819,9 +816,18 @@ export class Importer {
|
|
|
819
816
|
}
|
|
820
817
|
|
|
821
818
|
if (reference) {
|
|
822
|
-
const drawing =
|
|
819
|
+
const drawing = this.workbook.ReadDrawing(reference);
|
|
823
820
|
if (drawing && drawing.length) {
|
|
824
|
-
|
|
821
|
+
for (const entry of drawing) {
|
|
822
|
+
switch (entry.type) {
|
|
823
|
+
case 'chart':
|
|
824
|
+
chart_descriptors.push(entry);
|
|
825
|
+
break;
|
|
826
|
+
case 'image':
|
|
827
|
+
image_descriptors.push(entry);
|
|
828
|
+
break;
|
|
829
|
+
}
|
|
830
|
+
}
|
|
825
831
|
}
|
|
826
832
|
}
|
|
827
833
|
|
|
@@ -861,6 +867,40 @@ export class Importer {
|
|
|
861
867
|
|
|
862
868
|
};
|
|
863
869
|
|
|
870
|
+
for (const descriptor of image_descriptors) {
|
|
871
|
+
if (descriptor && descriptor.image) {
|
|
872
|
+
|
|
873
|
+
const layout: AnnotationLayout = {
|
|
874
|
+
tl: AnchorToCorner(descriptor.anchor.from),
|
|
875
|
+
br: AnchorToCorner(descriptor.anchor.to),
|
|
876
|
+
};
|
|
877
|
+
|
|
878
|
+
let type: AnnotationType = 'image';
|
|
879
|
+
const data = Base64JS.fromByteArray(descriptor.image);
|
|
880
|
+
let imagetype: string = '';
|
|
881
|
+
|
|
882
|
+
if (descriptor.filename) {
|
|
883
|
+
if (/jpe*g$/i.test(descriptor.filename)) {
|
|
884
|
+
imagetype = 'jpeg';
|
|
885
|
+
}
|
|
886
|
+
else if (/png$/i.test(descriptor.filename)) {
|
|
887
|
+
imagetype = 'png';
|
|
888
|
+
}
|
|
889
|
+
else if (/gif$/i.test(descriptor.filename)) {
|
|
890
|
+
imagetype = 'gif';
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
if (imagetype && data) {
|
|
895
|
+
const src = 'data:image/' + imagetype + ';base64,' + data;
|
|
896
|
+
annotations.push({
|
|
897
|
+
layout, type, data: { src },
|
|
898
|
+
});
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
|
|
864
904
|
for (const descriptor of chart_descriptors) {
|
|
865
905
|
if (descriptor && descriptor.chart) {
|
|
866
906
|
|
|
@@ -19,8 +19,12 @@
|
|
|
19
19
|
*
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
import
|
|
22
|
+
import UZip from 'uzip';
|
|
23
|
+
|
|
24
|
+
// import type JSZip from 'jszip';
|
|
23
25
|
// import * as xmlparser from 'fast-xml-parser';
|
|
26
|
+
|
|
27
|
+
|
|
24
28
|
import { XMLParser } from 'fast-xml-parser';
|
|
25
29
|
import { XMLUtils, XMLOptions, XMLOptions2 } from './xml-utils';
|
|
26
30
|
|
|
@@ -39,6 +43,7 @@ import { StyleCache } from './workbook-style2';
|
|
|
39
43
|
import { Theme } from './workbook-theme2';
|
|
40
44
|
import { Sheet, VisibleState } from './workbook-sheet2';
|
|
41
45
|
import type { RelationshipMap } from './relationship';
|
|
46
|
+
import { ZipWrapper } from './zip-wrapper';
|
|
42
47
|
|
|
43
48
|
|
|
44
49
|
/*
|
|
@@ -79,11 +84,21 @@ export interface ChartDescription {
|
|
|
79
84
|
series?: ChartSeries[];
|
|
80
85
|
}
|
|
81
86
|
|
|
87
|
+
export interface AnchoredImageDescription {
|
|
88
|
+
type: 'image';
|
|
89
|
+
image?: Uint8Array;
|
|
90
|
+
filename?: string;
|
|
91
|
+
anchor: TwoCellAnchor,
|
|
92
|
+
}
|
|
93
|
+
|
|
82
94
|
export interface AnchoredChartDescription {
|
|
95
|
+
type: 'chart';
|
|
83
96
|
chart?: ChartDescription,
|
|
84
97
|
anchor: TwoCellAnchor,
|
|
85
98
|
}
|
|
86
99
|
|
|
100
|
+
export type AnchoredDrawingPart = AnchoredChartDescription|AnchoredImageDescription;
|
|
101
|
+
|
|
87
102
|
export interface TableFooterType {
|
|
88
103
|
type: 'label'|'formula';
|
|
89
104
|
value: string;
|
|
@@ -138,17 +153,17 @@ export class Workbook {
|
|
|
138
153
|
return this.sheets.length;
|
|
139
154
|
}
|
|
140
155
|
|
|
141
|
-
constructor(public zip:
|
|
156
|
+
constructor(public zip: ZipWrapper) {
|
|
142
157
|
|
|
143
158
|
}
|
|
144
159
|
|
|
145
160
|
/**
|
|
146
161
|
* given a path in the zip file, read and parse the rels file
|
|
147
162
|
*/
|
|
148
|
-
public
|
|
163
|
+
public ReadRels(path: string): RelationshipMap {
|
|
149
164
|
|
|
150
165
|
const rels: RelationshipMap = {};
|
|
151
|
-
const data =
|
|
166
|
+
const data = this.zip.Has(path) ? this.zip.Get(path) : '';
|
|
152
167
|
|
|
153
168
|
//
|
|
154
169
|
// force array on <Relationship/> elements, but be slack on the rest
|
|
@@ -169,30 +184,30 @@ export class Workbook {
|
|
|
169
184
|
|
|
170
185
|
}
|
|
171
186
|
|
|
172
|
-
public
|
|
187
|
+
public Init() {
|
|
173
188
|
|
|
174
189
|
// read workbook rels
|
|
175
|
-
this.rels =
|
|
176
|
-
|
|
190
|
+
this.rels = this.ReadRels( 'xl/_rels/workbook.xml.rels');
|
|
191
|
+
|
|
177
192
|
// shared strings
|
|
178
|
-
let data =
|
|
193
|
+
let data = this.zip.Has('xl/sharedStrings.xml') ? this.zip.Get('xl/sharedStrings.xml') : '';
|
|
179
194
|
let xml = xmlparser2.parse(data || '');
|
|
180
195
|
this.shared_strings.FromXML(xml);
|
|
181
196
|
|
|
182
197
|
// theme
|
|
183
|
-
data =
|
|
198
|
+
data = this.zip.Get('xl/theme/theme1.xml');
|
|
184
199
|
xml = xmlparser2.parse(data);
|
|
185
200
|
this.theme.FromXML(xml);
|
|
186
201
|
|
|
187
202
|
// styles
|
|
188
|
-
data =
|
|
203
|
+
data = this.zip.Get('xl/styles.xml');
|
|
189
204
|
xml = xmlparser2.parse(data);
|
|
190
205
|
this.style_cache.FromXML(xml, this.theme);
|
|
191
206
|
|
|
192
207
|
// console.info({c: this.style_cache});
|
|
193
208
|
|
|
194
209
|
// read workbook
|
|
195
|
-
data =
|
|
210
|
+
data = this.zip.Get('xl/workbook.xml');
|
|
196
211
|
xml = xmlparser2.parse(data);
|
|
197
212
|
|
|
198
213
|
// defined names
|
|
@@ -240,9 +255,9 @@ export class Workbook {
|
|
|
240
255
|
worksheet.path = `xl/${this.rels[rid].target}`;
|
|
241
256
|
worksheet.rels_path = worksheet.path.replace('worksheets', 'worksheets/_rels') + '.rels';
|
|
242
257
|
|
|
243
|
-
data =
|
|
258
|
+
data = this.zip.Get(worksheet.path);
|
|
244
259
|
worksheet.sheet_data = xmlparser2.parse(data || '');
|
|
245
|
-
worksheet.rels =
|
|
260
|
+
worksheet.rels = this.ReadRels(worksheet.rels_path);
|
|
246
261
|
|
|
247
262
|
worksheet.Parse();
|
|
248
263
|
// console.info("TS", worksheet);
|
|
@@ -256,9 +271,9 @@ export class Workbook {
|
|
|
256
271
|
|
|
257
272
|
}
|
|
258
273
|
|
|
259
|
-
public
|
|
274
|
+
public ReadTable(reference: string): TableDescription|undefined {
|
|
260
275
|
|
|
261
|
-
const data =
|
|
276
|
+
const data = this.zip.Get(reference.replace(/^../, 'xl'));
|
|
262
277
|
|
|
263
278
|
if (!data) {
|
|
264
279
|
return undefined;
|
|
@@ -276,19 +291,21 @@ export class Workbook {
|
|
|
276
291
|
};
|
|
277
292
|
|
|
278
293
|
return table;
|
|
294
|
+
|
|
279
295
|
}
|
|
280
296
|
|
|
281
|
-
public
|
|
297
|
+
public ReadDrawing(reference: string): AnchoredDrawingPart[] | undefined {
|
|
282
298
|
|
|
283
|
-
const data =
|
|
299
|
+
const data = this.zip.Get(reference.replace(/^../, 'xl'));
|
|
300
|
+
|
|
284
301
|
if (!data) {
|
|
285
302
|
return undefined;
|
|
286
303
|
}
|
|
287
304
|
const xml = xmlparser2.parse(data);
|
|
288
305
|
|
|
289
|
-
const drawing_rels =
|
|
306
|
+
const drawing_rels = this.ReadRels(reference.replace(/^..\/drawings/, 'xl/drawings/_rels') + '.rels');
|
|
290
307
|
|
|
291
|
-
const results:
|
|
308
|
+
const results: AnchoredDrawingPart[] = [];
|
|
292
309
|
const anchor_nodes = XMLUtils.FindAll(xml, 'xdr:wsDr/xdr:twoCellAnchor');
|
|
293
310
|
|
|
294
311
|
/* FIXME: move to drawing? */
|
|
@@ -308,18 +325,46 @@ export class Workbook {
|
|
|
308
325
|
from: ParseAnchor(anchor_node['xdr:from']),
|
|
309
326
|
to: ParseAnchor(anchor_node['xdr:to']),
|
|
310
327
|
};
|
|
311
|
-
const result: AnchoredChartDescription = { anchor };
|
|
312
328
|
|
|
313
329
|
const chart_reference = XMLUtils.FindAll(anchor_node, `xdr:graphicFrame/a:graphic/a:graphicData/c:chart`)[0];
|
|
314
330
|
|
|
315
331
|
if (chart_reference && chart_reference.a$ && chart_reference.a$['r:id']) {
|
|
332
|
+
const result: AnchoredChartDescription = { type: 'chart', anchor };
|
|
316
333
|
const chart_rel = drawing_rels[chart_reference.a$['r:id']];
|
|
317
334
|
if (chart_rel && chart_rel.target) {
|
|
318
|
-
result.chart =
|
|
335
|
+
result.chart = this.ReadChart(chart_rel.target);
|
|
319
336
|
}
|
|
337
|
+
results.push(result);
|
|
320
338
|
}
|
|
339
|
+
else {
|
|
321
340
|
|
|
322
|
-
|
|
341
|
+
const media_reference = XMLUtils.FindAll(anchor_node, `xdr:pic/xdr:blipFill/a:blip`)[0];
|
|
342
|
+
if (media_reference && media_reference.a$['r:embed']) {
|
|
343
|
+
const media_rel = drawing_rels[media_reference.a$['r:embed']];
|
|
344
|
+
|
|
345
|
+
// const chart_rel = drawing_rels[chart_reference.a$['r:id']];
|
|
346
|
+
// console.info("Maybe an image?", media_reference, media_rel)
|
|
347
|
+
|
|
348
|
+
if (media_rel && media_rel.target) {
|
|
349
|
+
if (/(?:jpg|jpeg|png|gif)$/i.test(media_rel.target)) {
|
|
350
|
+
|
|
351
|
+
// const result: AnchoredImageDescription = { type: 'image' };
|
|
352
|
+
const path = media_rel.target.replace(/^\.\./, 'xl');
|
|
353
|
+
const filename = path.replace(/^.*\//, '');
|
|
354
|
+
|
|
355
|
+
const result: AnchoredImageDescription = {
|
|
356
|
+
type: 'image', anchor, image: this.zip.GetBinary(path), filename
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
results.push(result);
|
|
360
|
+
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
}
|
|
323
368
|
|
|
324
369
|
}
|
|
325
370
|
|
|
@@ -332,9 +377,9 @@ export class Workbook {
|
|
|
332
377
|
* FIXME: this is using the old options with old structure, just have
|
|
333
378
|
* not updated it yet
|
|
334
379
|
*/
|
|
335
|
-
public
|
|
380
|
+
public ReadChart(reference: string): ChartDescription|undefined {
|
|
336
381
|
|
|
337
|
-
const data =
|
|
382
|
+
const data = this.zip.Get(reference.replace(/^../, 'xl'));
|
|
338
383
|
if (!data) { return undefined; }
|
|
339
384
|
|
|
340
385
|
const xml = xmlparser1.parse(data);
|