@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.
Files changed (44) hide show
  1. package/README.md +6 -0
  2. package/dist/treb-spreadsheet-light.mjs +16 -0
  3. package/dist/treb-spreadsheet.mjs +13 -11
  4. package/dist/treb.d.ts +33 -5
  5. package/esbuild-custom-element.mjs +3 -1
  6. package/package.json +8 -6
  7. package/treb-base-types/src/dom-utilities.ts +157 -19
  8. package/treb-base-types/src/import.ts +1 -0
  9. package/treb-base-types/src/theme.ts +5 -4
  10. package/treb-charts/src/renderer.ts +4 -58
  11. package/treb-embed/markup/layout.html +4 -0
  12. package/treb-embed/src/custom-element/spreadsheet-constructor.ts +131 -87
  13. package/treb-embed/src/embedded-spreadsheet.ts +153 -140
  14. package/treb-embed/src/options.ts +9 -0
  15. package/treb-embed/src/spinner.ts +5 -3
  16. package/treb-embed/src/toolbar-message.ts +5 -0
  17. package/treb-embed/style/layout.scss +65 -1
  18. package/treb-export/src/export-worker/export-worker.ts +7 -12
  19. package/treb-export/src/export2.ts +57 -33
  20. package/treb-export/src/import2.ts +61 -21
  21. package/treb-export/src/workbook2.ts +69 -24
  22. package/treb-export/src/zip-wrapper.ts +96 -0
  23. package/treb-grid/src/editors/autocomplete.ts +24 -13
  24. package/treb-grid/src/editors/editor.ts +43 -139
  25. package/treb-grid/src/editors/external_editor.ts +1 -1
  26. package/treb-grid/src/editors/formula_bar.ts +24 -24
  27. package/treb-grid/src/editors/overlay_editor.ts +1 -1
  28. package/treb-grid/src/layout/base_layout.ts +34 -25
  29. package/treb-grid/src/layout/grid_layout.ts +20 -20
  30. package/treb-grid/src/render/selection-renderer.ts +3 -3
  31. package/treb-grid/src/render/svg_header_overlay.ts +6 -4
  32. package/treb-grid/src/render/svg_selection_block.ts +10 -7
  33. package/treb-grid/src/types/annotation.ts +2 -2
  34. package/treb-grid/src/types/grid.ts +80 -81
  35. package/treb-grid/src/types/scale-control.ts +69 -81
  36. package/treb-grid/src/types/sheet.ts +3 -52
  37. package/treb-grid/src/types/tab_bar.ts +27 -13
  38. package/treb-grid/src/util/fontmetrics2.ts +24 -21
  39. package/treb-utils/src/event_source.ts +23 -23
  40. package/treb-utils/src/index.ts +2 -2
  41. package/treb-utils/src/measurement.ts +24 -24
  42. package/treb-utils/src/serialize_html.ts +25 -21
  43. package/treb-utils/src/dispatch.ts +0 -57
  44. 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 async Init(decorated_functions: Record<string, string> = {}): Promise<void> {
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
- this.zip = await new JSZip().loadAsync(template, {base64: true});
143
+ const parsed = Base64JS.toByteArray(template);
144
+ this.zip = new ZipWrapper(parsed);
141
145
 
142
146
  }
143
147
 
144
- public async WriteRels(rels: RelationshipMap, path: string, dump = false): Promise<void> {
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
- await this.zip?.file(path, xml);
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 async WriteStyleCache(style_cache: StyleCache): Promise<void> {
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
- await this.zip?.file('xl/styles.xml', xml);
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 async WriteSharedStrings(shared_strings: SharedStrings): Promise<void> {
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
- await this.zip?.file('xl/sharedStrings.xml', xml);
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 async Export(source: {
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
- }): Promise<void> {
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 = await this.zip?.file('xl/theme/theme1.xml')?.async('text') as string;
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 = await this.zip?.file('xl/styles.xml')?.async('text') as string;
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
- await this.zip?.file(`xl/tables/table${table.index}.xml`, xml);
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
- // console.info({image}, `xl/media/image${image.index}.${image.extension}`);
2308
- await this.zip?.file(`xl/media/image${image.index}.${image.extension}`, image.options.data||'', {
2309
- base64: image.options.encoding === 'base64'
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
- await this.zip?.file(`xl/charts/chart${chart.index}.xml`, xml);
2318
- await this.WriteRels(chart.relationships, `xl/charts/_rels/chart${chart.index}.xml.rels`);
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
- await this.WriteRels(drawing.relationships, `xl/drawings/_rels/drawing${drawing.index}.xml.rels`);
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
- await this.zip?.file(`xl/drawings/drawing${drawing.index}.xml`, xml);
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
- await this.zip?.file(`xl/worksheets/sheet${sheet_index + 1}.xml`, xml);
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
- await this.WriteSharedStrings(shared_strings);
2373
- await this.WriteStyleCache(style_cache);
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
- await this.WriteRels(workbook_rels, `xl/_rels/workbook.xml.rels`);
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
- await this.zip?.file(`xl/workbook.xml`, workbook_xml);
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
- await this.zip?.file(`[Content_Types].xml`, content_types_xml);
2570
+ this.zip?.Set(`[Content_Types].xml`, content_types_xml);
2564
2571
 
2565
2572
  }
2566
2573
 
2567
- /** zip -> binary string */
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
- /** zip -> blob */
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 * as JSZip from 'jszip';
23
- import JSZip from 'jszip';
22
+ // import JSZip from 'jszip';
24
23
 
25
- import type { AnchoredChartDescription} from './workbook2';
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
- if (typeof data === 'string') {
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 async GetSheet(index = 0): Promise<ImportedSheetData> {
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 = await this.workbook.ReadTable(reference);
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 = await this.workbook.ReadDrawing(reference);
819
+ const drawing = this.workbook.ReadDrawing(reference);
823
820
  if (drawing && drawing.length) {
824
- chart_descriptors.push(...drawing);
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 type JSZip from 'jszip';
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: JSZip) {
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 async ReadRels(path: string): Promise<RelationshipMap> {
163
+ public ReadRels(path: string): RelationshipMap {
149
164
 
150
165
  const rels: RelationshipMap = {};
151
- const data = await this.zip.file(path)?.async('text') as string;
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 async Init(): Promise<void> {
187
+ public Init() {
173
188
 
174
189
  // read workbook rels
175
- this.rels = await this.ReadRels( 'xl/_rels/workbook.xml.rels');
176
-
190
+ this.rels = this.ReadRels( 'xl/_rels/workbook.xml.rels');
191
+
177
192
  // shared strings
178
- let data = await this.zip.file('xl/sharedStrings.xml')?.async('text') as string;
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 = await this.zip.file('xl/theme/theme1.xml')?.async('text') as string;
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 = await this.zip.file('xl/styles.xml')?.async('text') as string;
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 = await this.zip.file('xl/workbook.xml')?.async('text') as string;
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 = await this.zip.file(worksheet.path)?.async('text') as string;
258
+ data = this.zip.Get(worksheet.path);
244
259
  worksheet.sheet_data = xmlparser2.parse(data || '');
245
- worksheet.rels = await this.ReadRels(worksheet.rels_path);
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 async ReadTable(reference: string): Promise<TableDescription|undefined> {
274
+ public ReadTable(reference: string): TableDescription|undefined {
260
275
 
261
- const data = await this.zip.file(reference.replace(/^../, 'xl'))?.async('text') as string;
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 async ReadDrawing(reference: string): Promise<AnchoredChartDescription[] | undefined> {
297
+ public ReadDrawing(reference: string): AnchoredDrawingPart[] | undefined {
282
298
 
283
- const data = await this.zip.file(reference.replace(/^../, 'xl'))?.async('text') as string;
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 = await this.ReadRels(reference.replace(/^..\/drawings/, 'xl/drawings/_rels') + '.rels');
306
+ const drawing_rels = this.ReadRels(reference.replace(/^..\/drawings/, 'xl/drawings/_rels') + '.rels');
290
307
 
291
- const results: AnchoredChartDescription[] = [];
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 = await this.ReadChart(chart_rel.target);
335
+ result.chart = this.ReadChart(chart_rel.target);
319
336
  }
337
+ results.push(result);
320
338
  }
339
+ else {
321
340
 
322
- results.push(result);
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 async ReadChart(reference: string): Promise<ChartDescription|undefined> {
380
+ public ReadChart(reference: string): ChartDescription|undefined {
336
381
 
337
- const data = await this.zip.file(reference.replace(/^../, 'xl'))?.async('text') as string;
382
+ const data = this.zip.Get(reference.replace(/^../, 'xl'));
338
383
  if (!data) { return undefined; }
339
384
 
340
385
  const xml = xmlparser1.parse(data);