@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
@@ -65,10 +65,10 @@ import type {
65
65
 
66
66
  import {
67
67
  IsArea, ThemeColorTable, ComplexToString, Rectangle, IsComplex, type CellStyle,
68
- Localization, Style, type Color, ThemeColor2, IsCellAddress, Area, IsFlatData, IsFlatDataArray, Gradient, ValueType, DOMUtilities,
68
+ Localization, Style, type Color, ThemeColor2, IsCellAddress, Area, IsFlatData, IsFlatDataArray, Gradient, ValueType, DOMContext,
69
69
  } from 'treb-base-types';
70
70
 
71
- import { EventSource, Yield, ValidateURI } from 'treb-utils';
71
+ import { EventSource, ValidateURI } from 'treb-utils';
72
72
  import { NumberFormatCache, ValueParser, NumberFormat } from 'treb-format';
73
73
 
74
74
 
@@ -232,15 +232,17 @@ export class EmbeddedSpreadsheet {
232
232
  /** @internal */
233
233
  public static treb_embedded_script_path = '';
234
234
 
235
- /** @internal */
236
- public static enable_engine = false;
235
+ /* * @internal */
236
+ // public static enable_engine = false;
237
237
 
238
- /** @internal */
239
- public static enable_formatter = false;
238
+ /* * @internal */
239
+ // public static enable_formatter = false;
240
240
 
241
241
  /** @internal */
242
242
  public static one_time_warnings: Record<string, boolean> = {};
243
243
 
244
+ protected DOM = DOMContext.GetInstance(); // default
245
+
244
246
  /**
245
247
  * this flag will be set on LoadDocument. the intent is to be able to
246
248
  * know if you have loaded a network document, which may happen before you
@@ -253,10 +255,10 @@ export class EmbeddedSpreadsheet {
253
255
  */
254
256
  public loaded = false;
255
257
 
256
- /**
258
+ /* *
257
259
  * @internal
258
260
  */
259
- public toolbar_ctl?: ToolbarCtl;
261
+ // public toolbar_ctl?: ToolbarCtl;
260
262
 
261
263
  /**
262
264
  * this is a cache of number formats and colors used in the document. it's
@@ -334,6 +336,39 @@ export class EmbeddedSpreadsheet {
334
336
  */
335
337
  protected last_save_version = 0;
336
338
 
339
+ /* *
340
+ * this is an attempt to improve our recordkeeping for stuff that
341
+ * has user-generated changes. it means "this is the version that
342
+ * was in the network document or inline document". it has no
343
+ * meaning in sheets that start empty.
344
+ *
345
+ * we use "network version" to mean both network documents and inline
346
+ * documents (Which technically come from the network).
347
+ *
348
+ * the problem with this is that the only way for it to work would
349
+ * be to store it in the document, but once we start storing this
350
+ * value it will get stuck and cause problems. there's no way to
351
+ * "only store it in some contexts". I guess in theory we could wipe
352
+ * it if necesssary, but that's weak... something like
353
+ *
354
+ * (1) if this document comes from anywhere but local storage,
355
+ * dump the value
356
+ *
357
+ * (2) never save this value unless you're writing to local storage
358
+ *
359
+ * it's still going to get stuck in places it shouldn't be but we can
360
+ * mitigate problems with it. I'll think about it. we can do the
361
+ * "can revert" thing in a different way.
362
+ *
363
+ * /
364
+ protected canonical_network_version = 0;
365
+ */
366
+
367
+ /**
368
+ * simpler flag for testing if we can revert
369
+ */
370
+ protected initial_load_source: LoadSource|undefined = undefined;
371
+
337
372
  /**
338
373
  * calculator instance. we may share this if we're in a split view.
339
374
  */
@@ -487,6 +522,50 @@ export class EmbeddedSpreadsheet {
487
522
  return this.file_version;
488
523
  }
489
524
 
525
+ /**
526
+ * this flag indicates we can revert the document. what that means is
527
+ * we loaded a user-created version from localStorage, but there's a
528
+ * backing network or inline document. or we did load the original version
529
+ * but the user has made some document changes.
530
+ *
531
+ * it's like `dirty`, but that uses the load source as the ground truth,
532
+ * which means if you load a modified document from localStorage it's
533
+ * initially considered not-dirty (which is maybe just a bad design?)
534
+ *
535
+ * the intent of this field is to support enabling/disabling revert
536
+ * logic, or to add a visual indicator that you are not looking at the
537
+ * canonical version.
538
+ *
539
+ * @privateRemarks
540
+ * for that to work we need to know that we loaded from localStorage --
541
+ * that's not something we're keeping track of at the moment.
542
+ *
543
+ * it might be good to include the "canonical version" when we put stuff
544
+ * in localStorage...
545
+ *
546
+ */
547
+ public get can_revert(): boolean {
548
+
549
+ // first check we came from a network source.
550
+
551
+ if (!this.options.inline_document && !this.options.document) {
552
+ return false;
553
+ }
554
+
555
+ // next check if we actually loaded from localStorage. for the purposes
556
+ // of this state check we only care about the initial load, so we can
557
+ // store that.
558
+
559
+ if (this.initial_load_source === LoadSource.LOCAL_STORAGE) {
560
+ return true;
561
+ }
562
+
563
+ // last check dirty -- that's everything else
564
+
565
+ return this.dirty;
566
+
567
+ }
568
+
490
569
  /**
491
570
  * indicates the current revision of the document is not equal to the
492
571
  * last-saved revision of the document.
@@ -672,6 +751,7 @@ export class EmbeddedSpreadsheet {
672
751
  if (options.model) {
673
752
  this.model = options.model.model;
674
753
  this.calculator = options.model.calculator; // as CalcType;
754
+ this.DOM = options.model.DOM;
675
755
  }
676
756
  else {
677
757
 
@@ -692,11 +772,15 @@ export class EmbeddedSpreadsheet {
692
772
  //this.extra_calculator = //new Calculator(this.model);
693
773
  // this.CreateCalculator(this.model);
694
774
 
775
+ if (container) {
776
+ this.DOM = DOMContext.GetInstance(container.ownerDocument);
777
+ }
778
+
695
779
  // update: tell the grid if we don't want to initialize the DOM,
696
780
  // if we don't have a container. that's distinct (at the moment)
697
781
  // from headless, which is a state that can change.
698
782
 
699
- this.grid = new Grid(grid_options, this.model, undefined, !!container);
783
+ this.grid = new Grid(grid_options, this.model, undefined, !!container, this.DOM);
700
784
 
701
785
  if (this.options.headless) {
702
786
  this.grid.headless = true; // FIXME: move into grid options
@@ -706,6 +790,8 @@ export class EmbeddedSpreadsheet {
706
790
 
707
791
  if (container) {
708
792
 
793
+ this.DOM = DOMContext.GetInstance(container.ownerDocument);
794
+
709
795
  // if this is the first one, update UA classes (used to be in grid)
710
796
 
711
797
  if (!this.parent_view) {
@@ -1003,80 +1089,6 @@ export class EmbeddedSpreadsheet {
1003
1089
 
1004
1090
  }
1005
1091
 
1006
- /**
1007
- * we need to load relative resources. we can't access the path of this
1008
- * script, but because it has to be added via a script tag -- either
1009
- * statically or dynamically -- we should be able to get it.
1010
- *
1011
- * it is possible that the script tag goes away, but if we sniff on first
1012
- * script execution, we can probably assume it's still there -- because the
1013
- * client won't have had a chance to remove it yet.
1014
- *
1015
- * @internal
1016
- */
1017
- public static BuildPath(): void {
1018
- const tags = (typeof document === 'undefined') ? [] : document.querySelectorAll('script');
1019
-
1020
- // FIXME: fragile!
1021
- const default_script_name = process.env.BUILD_ENTRY_MAIN || '';
1022
- let rex = new RegExp(default_script_name);
1023
-
1024
- // tslint:disable-next-line:prefer-for-of
1025
- for (let i = 0; i < tags.length; i++) {
1026
-
1027
- const tag = tags[i];
1028
- const src = tag.src; // fully-qualified here [FIXME: IE11?]
1029
-
1030
- /*
1031
- if (src && /\?.*?engine/i.test(src)) {
1032
- console.info('s', src);
1033
- this.enable_engine = true;
1034
- }
1035
- */
1036
-
1037
- if (src && rex.test(src)) {
1038
-
1039
- /*
1040
- if (src && /\?.*?utils/i.test(src)) {
1041
- this.enable_utils = true;
1042
- }
1043
- */
1044
-
1045
- if (src && /\?.*?engine/i.test(src)) {
1046
- this.enable_engine = true;
1047
- }
1048
-
1049
- if (src && /\?.*?format/i.test(src)) {
1050
- this.enable_formatter = true;
1051
- }
1052
-
1053
- this.treb_embedded_script_path = src;
1054
- this.treb_base_path = src.replace(new RegExp(default_script_name + '.*$'), '');
1055
-
1056
- return;
1057
- }
1058
-
1059
- }
1060
-
1061
- // to support .mjs imports, look for the import line
1062
-
1063
- rex = new RegExp(`import.*?from.*?['"](.*?${default_script_name}.*?)['"]`);
1064
- for (let i = 0; i < tags.length; i++) {
1065
- const tag = tags[i];
1066
- if (!tag.src) {
1067
- const text = tag.textContent;
1068
- const match = (text||'').match(rex);
1069
- if (match) {
1070
- const src = match[1];
1071
- this.treb_embedded_script_path = src;
1072
- this.treb_base_path = src.replace(new RegExp(default_script_name + '.*$'), '');
1073
- return;
1074
- }
1075
- }
1076
- }
1077
-
1078
- }
1079
-
1080
1092
  /**
1081
1093
  * update autocomplete functions. we're breaking this out into a
1082
1094
  * separate method so we can better manage language translation.
@@ -1872,6 +1884,17 @@ export class EmbeddedSpreadsheet {
1872
1884
  this.ShowSidebar(event.command === 'toggle-sidebar' ? undefined : event.command === 'show-sidebar');
1873
1885
  break;
1874
1886
 
1887
+ case 'revert-indicator':
1888
+ this.dialog?.ShowDialog({
1889
+ title: `This is a modified version of the document.\n` +
1890
+ `You can revert to the original or save your\n` +
1891
+ `changes in the sidebar.`,
1892
+ close_box: true,
1893
+ timeout: 5000,
1894
+ type: DialogType.info,
1895
+ });
1896
+ break;
1897
+
1875
1898
  default:
1876
1899
  console.info('unhandled', event.command);
1877
1900
  break;
@@ -2676,13 +2699,18 @@ export class EmbeddedSpreadsheet {
2676
2699
  }
2677
2700
 
2678
2701
  /**
2679
- * revert to the network version of this document, if both `local_storage`
2680
- * and `network_document` are set.
2702
+ * revert to the network version of this document, if `local_storage`
2703
+ * is set and the create options had either `document` or `inline-document`
2704
+ * set.
2705
+ *
2706
+ * FIXME: we should adjust for documents that fail to load.
2681
2707
  */
2682
2708
  public Revert(): void {
2683
2709
 
2684
2710
  if (this.options.inline_document) {
2685
2711
  this.LoadDocument(this.options.inline_document);
2712
+ this.initial_load_source = LoadSource.INLINE_DOCUMENT; // update this flag, even though it's not "initial"
2713
+
2686
2714
  if (this.options.local_storage) {
2687
2715
  this.SaveLocalStorage('reverted_backup');
2688
2716
  localStorage.removeItem(this.options.local_storage);
@@ -2704,6 +2732,7 @@ export class EmbeddedSpreadsheet {
2704
2732
  */
2705
2733
 
2706
2734
  this.LoadNetworkDocument(canonical);
2735
+ this.initial_load_source = LoadSource.NETWORK_FILE; // update this flag, even though it's not "initial"
2707
2736
 
2708
2737
  // flush storage? what about mistakes? maybe we should
2709
2738
  // back it up somewhere? (...)
@@ -3203,6 +3232,10 @@ export class EmbeddedSpreadsheet {
3203
3232
  return this.parent_view.LoadDocument(data, options);
3204
3233
  }
3205
3234
 
3235
+ if (!this.initial_load_source) {
3236
+ this.initial_load_source = options.source;
3237
+ }
3238
+
3206
3239
  // API v1 OK
3207
3240
 
3208
3241
  /*
@@ -3298,7 +3331,7 @@ export class EmbeddedSpreadsheet {
3298
3331
 
3299
3332
  if (options.scroll) {
3300
3333
  const scroll = options.scroll;
3301
- Yield().then(() => this.ScrollTo(scroll));
3334
+ Promise.resolve().then(() => this.ScrollTo(scroll));
3302
3335
  }
3303
3336
 
3304
3337
  }
@@ -4343,7 +4376,7 @@ export class EmbeddedSpreadsheet {
4343
4376
  */
4344
4377
  protected SaveAs(blob: Blob, filename: string) {
4345
4378
 
4346
- const a = DOMUtilities.Create('a');
4379
+ const a = this.DOM.Create('a');
4347
4380
  a.href = URL.createObjectURL(blob);
4348
4381
  a.download = filename;
4349
4382
  a.click();
@@ -4357,7 +4390,8 @@ export class EmbeddedSpreadsheet {
4357
4390
  /**
4358
4391
  *
4359
4392
  */
4360
- protected async ImportXLSX(data: string, source: LoadSource): Promise<Blob | void> {
4393
+ protected async ImportXLSX( // data: string, source: LoadSource): Promise<Blob | void> {
4394
+ data: ArrayBuffer, source: LoadSource): Promise<Blob | void> {
4361
4395
 
4362
4396
  // this is inlined to ensure the code will be tree-shaken properly
4363
4397
  if (!process.env.XLSX_SUPPORT) {
@@ -4468,7 +4502,7 @@ export class EmbeddedSpreadsheet {
4468
4502
  return;
4469
4503
  }
4470
4504
 
4471
- const a = DOMUtilities.Create('a');
4505
+ const a = this.DOM.Create('a');
4472
4506
  a.setAttribute('target', this.options.hyperlinks);
4473
4507
  a.setAttribute('href', data);
4474
4508
  a.setAttribute('noreferrer', 'true');
@@ -4609,27 +4643,29 @@ export class EmbeddedSpreadsheet {
4609
4643
  protected SelectFile2(accept: string, operation: FileChooserOperation) {
4610
4644
 
4611
4645
  if (!this.file_chooser) {
4612
- this.file_chooser = DOMUtilities.Create('input');
4613
- this.file_chooser.type = 'file';
4614
-
4615
- const file_chooser = this.file_chooser;
4616
- file_chooser.addEventListener('change', () => {
4617
- if (file_chooser.files && file_chooser.files[0]) {
4618
- const file = file_chooser.files[0];
4619
- file_chooser.value = '';
4620
- switch (this.file_chooser_operation) {
4621
- case FileChooserOperation.InsertImage:
4622
- this.InsertImageInternal(file);
4623
- break;
4624
- case FileChooserOperation.LoadFile:
4625
- this.LoadFileInternal(file, LoadSource.LOCAL_FILE, true);
4626
- break;
4627
- default:
4628
- console.warn('file chooser: no operation');
4629
- break;
4630
- }
4631
- }
4646
+ const file_chooser = this.DOM.Create('input', undefined, undefined, {
4647
+ attrs: { type: 'file' },
4648
+ events: {
4649
+ change: () => {
4650
+ if (file_chooser.files && file_chooser.files[0]) {
4651
+ const file = file_chooser.files[0];
4652
+ file_chooser.value = '';
4653
+ switch (this.file_chooser_operation) {
4654
+ case FileChooserOperation.InsertImage:
4655
+ this.InsertImageInternal(file);
4656
+ break;
4657
+ case FileChooserOperation.LoadFile:
4658
+ this.LoadFileInternal(file, LoadSource.LOCAL_FILE, true);
4659
+ break;
4660
+ default:
4661
+ console.warn('file chooser: no operation');
4662
+ break;
4663
+ }
4664
+ }
4665
+ },
4666
+ },
4632
4667
  });
4668
+ this.file_chooser = file_chooser;
4633
4669
  }
4634
4670
 
4635
4671
  if (!this.file_chooser) {
@@ -4686,7 +4722,7 @@ export class EmbeddedSpreadsheet {
4686
4722
  }
4687
4723
  }
4688
4724
 
4689
- const img = DOMUtilities.Create('img');
4725
+ const img = this.DOM.Create('img');
4690
4726
  img.src = contents;
4691
4727
 
4692
4728
  // this is to let the browser figure out the image size.
@@ -4784,30 +4820,12 @@ export class EmbeddedSpreadsheet {
4784
4820
  this.LoadCSV(reader.result as string, source);
4785
4821
  }
4786
4822
  else if (process.env.XLSX_SUPPORT && /\.xls[xm]$/i.test(file.name)) {
4787
- let contents: string;
4788
-
4789
4823
  if (typeof reader.result === 'string') {
4790
- contents = reader.result;
4824
+ finalize('Unsupported file');
4791
4825
  }
4792
- else { // IE11
4793
-
4794
- /* can break on large blob
4795
- contents = String.fromCharCode.apply(null,
4796
- (new Uint8Array(reader.result as ArrayBuffer) as any));
4797
- */
4798
-
4799
- // FIXME: chunk
4800
-
4801
- contents = '';
4802
- const bytes = new Uint8Array(reader.result);
4803
- for (let i = 0; i < bytes.byteLength; i++) {
4804
- contents += String.fromCharCode(bytes[i]);
4805
- }
4806
-
4826
+ else {
4827
+ this.ImportXLSX(reader.result, source).then(() => finalize()).catch(err => finalize(err));
4807
4828
  }
4808
-
4809
- this.ImportXLSX(contents, source).then(() => finalize()).catch(err => finalize(err));
4810
-
4811
4829
  return;
4812
4830
  }
4813
4831
  else {
@@ -4829,13 +4847,8 @@ export class EmbeddedSpreadsheet {
4829
4847
  // FIXME: this should be done async, possibly in a worker
4830
4848
 
4831
4849
  setTimeout(() => {
4832
- if (/\.xlsx$/i.test(file.name)) {
4833
- if (reader.readAsBinaryString) {
4834
- reader.readAsBinaryString(file);
4835
- }
4836
- else {
4837
- reader.readAsArrayBuffer(file); // IE11
4838
- }
4850
+ if (/\.xls[xm]$/i.test(file.name)) {
4851
+ reader.readAsArrayBuffer(file);
4839
4852
  }
4840
4853
  else {
4841
4854
  reader.readAsText(file);
@@ -5051,7 +5064,7 @@ export class EmbeddedSpreadsheet {
5051
5064
  const reference = ValidateURI(annotation.data.data.src);
5052
5065
  if (reference) {
5053
5066
 
5054
- const img = DOMUtilities.Create('img');
5067
+ const img = this.DOM.Create('img');
5055
5068
  img.src = reference;
5056
5069
 
5057
5070
  if (annotation.data.data.scale === 'fixed') {
@@ -5081,7 +5094,7 @@ export class EmbeddedSpreadsheet {
5081
5094
  */
5082
5095
  protected DocumentChange(undo_selection?: string): void {
5083
5096
 
5084
- Yield().then(() => {
5097
+ Promise.resolve().then(() => {
5085
5098
 
5086
5099
  // console.info('serializing');
5087
5100
 
@@ -94,6 +94,9 @@ export interface EmbeddedSpreadsheetOptions {
94
94
  /** add resizable wrapper */
95
95
  resizable?: boolean;
96
96
 
97
+ /** even if we allow resizing, constrain width. this is to support fixed width columns. */
98
+ constrain_width?: boolean;
99
+
97
100
  /** export to xlsx, now optional */
98
101
  export?: boolean;
99
102
 
@@ -266,6 +269,12 @@ export interface EmbeddedSpreadsheetOptions {
266
269
  */
267
270
  revert_button?: boolean;
268
271
 
272
+ /**
273
+ * show the revert indicator. this is an indicator that shows on the
274
+ * top-left of the spreadsheet when a network document has local changes.
275
+ */
276
+ revert_indicator?: boolean;
277
+
269
278
  }
270
279
 
271
280
  /**
@@ -19,7 +19,7 @@
19
19
  *
20
20
  */
21
21
 
22
- import { DOMUtilities } from 'treb-base-types';
22
+ import { DOMContext } from 'treb-base-types';
23
23
 
24
24
  export class Spinner {
25
25
 
@@ -27,8 +27,10 @@ export class Spinner {
27
27
  private visible = false;
28
28
 
29
29
  constructor(public container: HTMLElement) {
30
- this.node = DOMUtilities.Div('treb-spinner', container);
31
- this.node.innerHTML = `<div><div></div><div></div><div></div><div></div></div>`;
30
+ const DOM = DOMContext.GetInstance(container.ownerDocument);
31
+ this.node = DOM.Div('treb-spinner', container, {
32
+ html: `<div><div></div><div></div><div></div><div></div></div>`,
33
+ });
32
34
  }
33
35
 
34
36
  public Show(): void {
@@ -76,6 +76,10 @@ export interface UIToolbarMessage {
76
76
  command: 'toggle-toolbar'|'show-toolbar'|'hide-toolbar'|'toggle-sidebar'|'show-sidebar'|'hide-sidebar';
77
77
  }
78
78
 
79
+ export interface RevertIndicatorMessage {
80
+ command: 'revert-indicator';
81
+ }
82
+
79
83
  export type ToolbarMessage
80
84
  = SetColorToolbarMessage
81
85
  | CommentToolbarMessage
@@ -87,6 +91,7 @@ export type ToolbarMessage
87
91
  | AnnotationToolbarMessage
88
92
  | PrecisionToolbarMessage
89
93
  | JustifyToolbarMessage
94
+ | RevertIndicatorMessage
90
95
  | AlignToolbarMessage
91
96
  | TableToolbarMessage
92
97
  | CommandToolbarMessage
@@ -187,6 +187,13 @@
187
187
 
188
188
  }
189
189
 
190
+ .treb-views.treb-can-revert .treb-view {
191
+ .treb-revert-indicator {
192
+ opacity: 1;
193
+ pointer-events: initial;
194
+ }
195
+ }
196
+
190
197
  .treb-view {
191
198
 
192
199
  position: relative;
@@ -219,6 +226,50 @@
219
226
  display: none;
220
227
  }
221
228
 
229
+ .treb-revert-indicator {
230
+ display: none;
231
+ }
232
+
233
+ &:first-of-type {
234
+
235
+ .treb-revert-indicator {
236
+ display: block;
237
+ grid-area: 2/1/3/2; // overlap the grid body
238
+ justify-self: start;
239
+ align-self: start;
240
+ width: 1rem;
241
+ height: 1rem;
242
+ position: relative;
243
+ overflow: hidden;
244
+ opacity: 0;
245
+ transition: opacity .125s ease;
246
+ pointer-events: none;
247
+
248
+ /* rounded style
249
+ &::after {
250
+ content: '';
251
+ position: absolute;
252
+ display: block;
253
+ top: -1rem;
254
+ left: -1rem;
255
+ border-radius: 1rem;
256
+ border: 1rem solid orange;
257
+ }
258
+ */
259
+
260
+ /* triangular style */
261
+
262
+ border: .5em solid orange;
263
+ border-right-color: transparent;
264
+ border-bottom-color: transparent;
265
+
266
+ /* end styles */
267
+
268
+ z-index: 20; // FIXME: use stack
269
+ }
270
+
271
+ }
272
+
222
273
  &:last-of-type {
223
274
 
224
275
  .treb-layout-resize-handle {
@@ -331,8 +382,21 @@
331
382
  -webkit-mask-image: var(--icon);
332
383
  }
333
384
 
385
+ // working on how to alter the revert button depending on state...
386
+ // remove hover effect? remove the button? (...)
387
+
388
+ /*
389
+ &:not(.sidebar-disabled):hover::after{
390
+ background: #666; // FIXME
391
+ }
392
+ */
393
+
394
+ &[data-can-revert=false] {
395
+ display: none;
396
+ }
397
+
334
398
  &:hover::after {
335
- background: #666;
399
+ background: #666; // FIXME
336
400
  }
337
401
 
338
402
  &[data-command=recalculate] {
@@ -27,27 +27,22 @@ import { Importer } from '../import2';
27
27
  const ctx: Worker = self as any;
28
28
  const exporter = new Exporter();
29
29
 
30
- const ExportSheets = async (data: any) => {
30
+ const ExportSheets = (data: any) => {
31
31
 
32
32
  if (data.sheet) {
33
- await exporter.Init(data.decorated || []);
34
- await exporter.Export(data.sheet);
35
-
36
- const blob = await exporter.AsBlob(1);
37
- const corrected = (blob as Blob).slice(0, (blob as Blob).size,
38
- 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
39
-
40
- ctx.postMessage({ status: 'complete', blob: corrected });
33
+ exporter.Init(data.decorated || []);
34
+ exporter.Export(data.sheet);
35
+ ctx.postMessage({ status: 'complete', blob: exporter.Blob() });
41
36
  }
42
37
 
43
38
  };
44
39
 
45
- const ImportSheet = async (data: any) => {
40
+ const ImportSheet = (data: any) => {
46
41
 
47
42
  const importer = new Importer();
48
43
 
49
44
  try {
50
- await importer.Init(data.data);
45
+ importer.Init(data.data);
51
46
 
52
47
  const count = importer.SheetCount();
53
48
  const results = {
@@ -57,7 +52,7 @@ const ImportSheet = async (data: any) => {
57
52
  };
58
53
 
59
54
  for (let i = 0; i < count; i++) {
60
- const result = await importer.GetSheet(i);
55
+ const result = importer.GetSheet(i);
61
56
  if (result) {
62
57
  results.sheets.push(result);
63
58
  }