@trebco/treb 27.9.0 → 27.11.4
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/dist/treb-spreadsheet.mjs +9 -9
- package/dist/treb.d.ts +8 -6
- package/package.json +1 -1
- package/{treb-grid/src/util/dom_utilities.ts → treb-base-types/src/dom-utilities.ts} +29 -20
- package/treb-base-types/src/index.ts +1 -0
- package/treb-base-types/src/theme.ts +3 -5
- package/treb-embed/src/custom-element/global.d.ts +3 -1
- package/treb-embed/src/custom-element/spreadsheet-constructor.ts +13 -19
- package/treb-embed/src/embedded-spreadsheet.ts +67 -93
- package/treb-embed/src/spinner.ts +3 -3
- package/treb-embed/style/layout.scss +1 -1
- package/treb-embed/style/overlay-editor.scss +9 -0
- package/treb-export/src/drawing2/chart2.ts +11 -2
- package/treb-export/src/export2.ts +14 -4
- package/treb-export/src/workbook-style2.ts +3 -2
- package/treb-grid/src/editors/autocomplete.ts +28 -24
- package/treb-grid/src/editors/editor.ts +32 -4
- package/treb-grid/src/editors/formula_bar.ts +1 -1
- package/treb-grid/src/layout/base_layout.ts +11 -16
- package/treb-grid/src/layout/grid_layout.ts +17 -28
- package/treb-grid/src/render/selection-renderer.ts +2 -3
- package/treb-grid/src/render/svg_header_overlay.ts +4 -11
- package/treb-grid/src/render/svg_selection_block.ts +27 -34
- package/treb-grid/src/render/tile_renderer.ts +6 -5
- package/treb-grid/src/types/grid.ts +32 -41
- package/treb-grid/src/types/grid_base.ts +2 -0
- package/treb-grid/src/types/scale-control.ts +2 -2
- package/treb-grid/src/types/sheet.ts +2 -2
- package/treb-grid/src/types/tab_bar.ts +4 -8
- package/treb-utils/src/index.ts +0 -1
- package/treb-utils/src/resizable.ts +26 -27
- package/treb-utils/src/template.ts +0 -70
package/dist/treb.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! API v27.
|
|
1
|
+
/*! API v27.11. Copyright 2018-2023 trebco, llc. All rights reserved. LGPL: https://treb.app/license */
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* add our tag to the map
|
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
declare global {
|
|
7
7
|
interface HTMLElementTagNameMap {
|
|
8
8
|
'treb-spreadsheet': HTMLElement & {
|
|
9
|
-
|
|
9
|
+
instance: {
|
|
10
|
+
sheet: EmbeddedSpreadsheet | undefined;
|
|
11
|
+
} | undefined;
|
|
10
12
|
};
|
|
11
13
|
}
|
|
12
14
|
}
|
|
@@ -385,11 +387,11 @@ export declare class EmbeddedSpreadsheet {
|
|
|
385
387
|
* @param formula - annotation formula. For charts, the chart formula.
|
|
386
388
|
* @param type - annotation type. Defaults to `treb-chart`.
|
|
387
389
|
* @param rect - coordinates, or a range reference for layout.
|
|
388
|
-
*
|
|
389
|
-
*
|
|
390
|
-
*
|
|
390
|
+
* @param options - evaluate options. because this function used to take
|
|
391
|
+
* the argument separator, we allow that to be passed directly, but this
|
|
392
|
+
* is deprecated. new code should use the options object.
|
|
391
393
|
*/
|
|
392
|
-
InsertAnnotation(formula: string, type?: AnnotationType, rect?: IRectangle | RangeReference,
|
|
394
|
+
InsertAnnotation(formula: string, type?: AnnotationType, rect?: IRectangle | RangeReference, options?: EvaluateOptions | ',' | ';'): void;
|
|
393
395
|
|
|
394
396
|
/**
|
|
395
397
|
* Insert an image. This method will open a file chooser and (if an image
|
package/package.json
CHANGED
|
@@ -19,25 +19,50 @@
|
|
|
19
19
|
*
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
+
const SVGNS = 'http://www.w3.org/2000/svg';
|
|
23
|
+
|
|
22
24
|
export class DOMUtilities {
|
|
23
25
|
|
|
24
26
|
/** creates a div and assigns class name/names */
|
|
25
|
-
public static
|
|
27
|
+
public static Div(classes?: string|string[], parent?: HTMLElement, scope?: string): HTMLDivElement {
|
|
26
28
|
return this.Create('div', classes, parent, scope);
|
|
27
29
|
}
|
|
28
30
|
|
|
31
|
+
public static ClassNames(element: HTMLElement|SVGElement, classes: string|string[]) {
|
|
32
|
+
element.classList.add(...(Array.isArray(classes) ? classes : [classes]).reduce((arr: string[], entry) => [...arr, ...entry.split(/\s+/g)], []));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public static SVG<K extends keyof SVGElementTagNameMap>(
|
|
36
|
+
tag: K,
|
|
37
|
+
classes?: string|string[],
|
|
38
|
+
parent?: HTMLElement|SVGElement
|
|
39
|
+
): SVGElementTagNameMap[K] {
|
|
40
|
+
|
|
41
|
+
const element = document.createElementNS(SVGNS, tag);
|
|
42
|
+
|
|
43
|
+
if (classes) {
|
|
44
|
+
this.ClassNames(element, classes);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (parent) {
|
|
48
|
+
parent.appendChild(element);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return element;
|
|
52
|
+
}
|
|
53
|
+
|
|
29
54
|
/** better typing */
|
|
30
55
|
public static Create<K extends keyof HTMLElementTagNameMap>(
|
|
31
56
|
tag: K,
|
|
32
|
-
|
|
57
|
+
classes?: string|string[],
|
|
33
58
|
parent?: HTMLElement,
|
|
34
59
|
scope?: string,
|
|
35
60
|
attrs?: Record<string, string>): HTMLElementTagNameMap[K] {
|
|
36
61
|
|
|
37
62
|
const element = document.createElement(tag);
|
|
38
63
|
|
|
39
|
-
if (
|
|
40
|
-
element
|
|
64
|
+
if (classes) {
|
|
65
|
+
this.ClassNames(element, classes);
|
|
41
66
|
}
|
|
42
67
|
|
|
43
68
|
if (scope) {
|
|
@@ -58,20 +83,4 @@ export class DOMUtilities {
|
|
|
58
83
|
return element;
|
|
59
84
|
}
|
|
60
85
|
|
|
61
|
-
/* * generic element constructor. shame we need the tag AND the type. * /
|
|
62
|
-
public static Create1<E extends HTMLElement>(tag = '', classes = '', parent?: HTMLElement, scope?: string, attrs?: Record<string, string>){
|
|
63
|
-
const element = document.createElement(tag) as E;
|
|
64
|
-
if (classes) element.setAttribute('class', classes);
|
|
65
|
-
if (scope) element.setAttribute(scope, '');
|
|
66
|
-
if (attrs) {
|
|
67
|
-
const keys = Object.keys(attrs);
|
|
68
|
-
for (const key of keys) {
|
|
69
|
-
element.setAttribute(key, attrs[key]);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
if (parent) parent.appendChild(element);
|
|
73
|
-
return element;
|
|
74
|
-
}
|
|
75
|
-
*/
|
|
76
|
-
|
|
77
86
|
}
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
|
|
22
22
|
import type { Color, CellStyle } from './style';
|
|
23
23
|
import { ColorFunctions } from './color';
|
|
24
|
+
import { DOMUtilities } from './dom-utilities';
|
|
24
25
|
|
|
25
26
|
/*
|
|
26
27
|
* so this is a little strange. we use CSS to populate a theme object,
|
|
@@ -494,10 +495,7 @@ export const LoadThemeProperties = (container: HTMLElement): Theme => {
|
|
|
494
495
|
const theme: Theme = JSON.parse(JSON.stringify(DefaultTheme));
|
|
495
496
|
|
|
496
497
|
const Append = (parent: HTMLElement, classes: string): HTMLDivElement => {
|
|
497
|
-
|
|
498
|
-
node.setAttribute('class', classes);
|
|
499
|
-
parent.appendChild(node);
|
|
500
|
-
return node;
|
|
498
|
+
return DOMUtilities.Div(classes, parent);
|
|
501
499
|
}
|
|
502
500
|
|
|
503
501
|
const ElementCSS = (parent: HTMLElement, classes: string): CSSStyleDeclaration => {
|
|
@@ -574,7 +572,7 @@ export const LoadThemeProperties = (container: HTMLElement): Theme => {
|
|
|
574
572
|
// we could just parse, we know the returned css format is going
|
|
575
573
|
// to be an rgb triple (I think?)
|
|
576
574
|
|
|
577
|
-
const canvas =
|
|
575
|
+
const canvas = DOMUtilities.Create('canvas');
|
|
578
576
|
|
|
579
577
|
canvas.width = 3;
|
|
580
578
|
canvas.height = 3;
|
|
@@ -19,8 +19,11 @@ interface ElementOptions {
|
|
|
19
19
|
classes: string|string[];
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
/**
|
|
23
|
+
* FIXME: unify this with DOMUtils
|
|
24
|
+
*/
|
|
25
|
+
const Element = <K extends keyof HTMLElementTagNameMap>(tag: K, parent?: HTMLElement|DocumentFragment, options: Partial<ElementOptions> = {}, attrs: Record<string, string> = {}): HTMLElementTagNameMap[K] => {
|
|
26
|
+
const element = document.createElement(tag);
|
|
24
27
|
if (options.classes) {
|
|
25
28
|
|
|
26
29
|
// you can't use an array destructure in a ternary expression? TIL
|
|
@@ -105,21 +108,12 @@ export class SpreadsheetConstructor {
|
|
|
105
108
|
|
|
106
109
|
const style_node = document.head.querySelector('style[treb-stylesheet]');
|
|
107
110
|
if (!style_node) {
|
|
108
|
-
const style =
|
|
111
|
+
const style = Element('style');
|
|
109
112
|
style.setAttribute('treb-stylesheet', '');
|
|
110
113
|
style.textContent = css;
|
|
111
114
|
document.head.prepend(style);
|
|
112
115
|
}
|
|
113
116
|
|
|
114
|
-
/*
|
|
115
|
-
if (!SpreadsheetConstructor.stylesheets_attached) {
|
|
116
|
-
const style = document.createElement('style');
|
|
117
|
-
style.textContent = css;
|
|
118
|
-
document.head.prepend(style);
|
|
119
|
-
SpreadsheetConstructor.stylesheets_attached = true;
|
|
120
|
-
}
|
|
121
|
-
*/
|
|
122
|
-
|
|
123
117
|
}
|
|
124
118
|
|
|
125
119
|
}
|
|
@@ -509,9 +503,9 @@ export class SpreadsheetConstructor {
|
|
|
509
503
|
|
|
510
504
|
const resize_parent = root.querySelector('.treb-main') as HTMLElement; // was document.body
|
|
511
505
|
|
|
512
|
-
resizer = Element
|
|
506
|
+
resizer = Element('div', resize_parent, { classes: 'treb-resize-rect' });
|
|
513
507
|
|
|
514
|
-
mask = Element
|
|
508
|
+
mask = Element('div', resize_parent, {
|
|
515
509
|
classes: 'treb-resize-mask',
|
|
516
510
|
style: 'cursor: nw-resize;',
|
|
517
511
|
});
|
|
@@ -724,7 +718,7 @@ export class SpreadsheetConstructor {
|
|
|
724
718
|
}
|
|
725
719
|
|
|
726
720
|
}
|
|
727
|
-
Element
|
|
721
|
+
Element('button', fragment, { style, title, data: { command: 'set-color', color: JSON.stringify(entry.color) } });
|
|
728
722
|
}
|
|
729
723
|
}
|
|
730
724
|
|
|
@@ -733,7 +727,7 @@ export class SpreadsheetConstructor {
|
|
|
733
727
|
this.swatch_lists.theme?.replaceChildren(fragment);
|
|
734
728
|
|
|
735
729
|
fragment = document.createDocumentFragment();
|
|
736
|
-
Element
|
|
730
|
+
Element('button', fragment, {
|
|
737
731
|
classes: 'treb-default-color',
|
|
738
732
|
title: 'Default color',
|
|
739
733
|
data: { command: 'set-color', color: JSON.stringify({}) },
|
|
@@ -748,7 +742,7 @@ export class SpreadsheetConstructor {
|
|
|
748
742
|
|
|
749
743
|
for (const text of [...colors, ...additional_colors]) {
|
|
750
744
|
const style = `background: ${text.toLowerCase()};`;
|
|
751
|
-
Element
|
|
745
|
+
Element('button', fragment, { style, title: text, data: { command: 'set-color', color: JSON.stringify({text: text.toLowerCase()})}});
|
|
752
746
|
}
|
|
753
747
|
|
|
754
748
|
this.swatch_lists.other?.replaceChildren(fragment);
|
|
@@ -777,7 +771,7 @@ export class SpreadsheetConstructor {
|
|
|
777
771
|
}
|
|
778
772
|
|
|
779
773
|
const Button = (format: string) => {
|
|
780
|
-
return Element
|
|
774
|
+
return Element('button', undefined, {
|
|
781
775
|
text: format, data: { format, command: 'number-format' },
|
|
782
776
|
});
|
|
783
777
|
};
|
|
@@ -785,7 +779,7 @@ export class SpreadsheetConstructor {
|
|
|
785
779
|
const fragment = document.createDocumentFragment();
|
|
786
780
|
fragment.append(...number_formats.map(format => Button(format)));
|
|
787
781
|
|
|
788
|
-
fragment.append(Element
|
|
782
|
+
fragment.append(Element('div', undefined, {}, {separator: ''}));
|
|
789
783
|
fragment.append(...date_formats.map(format => Button(format)));
|
|
790
784
|
|
|
791
785
|
format_menu.textContent = '';
|
|
@@ -65,7 +65,7 @@ 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,
|
|
68
|
+
Localization, Style, type Color, ThemeColor2, IsCellAddress, Area, IsFlatData, IsFlatDataArray, Gradient, ValueType, DOMUtilities,
|
|
69
69
|
} from 'treb-base-types';
|
|
70
70
|
|
|
71
71
|
import { EventSource, Yield, ValidateURI } from 'treb-utils';
|
|
@@ -565,12 +565,33 @@ export class EmbeddedSpreadsheet {
|
|
|
565
565
|
// this one should not be done for a split view, but we should still
|
|
566
566
|
// do it if the toll flag is set, and storage key is set.
|
|
567
567
|
|
|
568
|
+
// FIXME: shouldn't this gate on dirty? (...)
|
|
569
|
+
// ALSO: check if we can use a different event. see
|
|
570
|
+
//
|
|
571
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event#usage_notes
|
|
572
|
+
//
|
|
573
|
+
// and, including the alternatives:
|
|
574
|
+
//
|
|
575
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/Window/unload_event
|
|
576
|
+
//
|
|
577
|
+
|
|
568
578
|
if (this.options.local_storage && !options.model ) {
|
|
579
|
+
|
|
580
|
+
window.addEventListener('visibilitychange', event => {
|
|
581
|
+
if (document.visibilityState === 'hidden') {
|
|
582
|
+
if (this.options.local_storage && this.dirty) {
|
|
583
|
+
this.SaveLocalStorage(this.options.local_storage);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
});
|
|
587
|
+
|
|
588
|
+
/*
|
|
569
589
|
window.addEventListener('beforeunload', () => {
|
|
570
|
-
if (this.options.local_storage) {
|
|
590
|
+
if (this.options.local_storage && this.dirty) {
|
|
571
591
|
this.SaveLocalStorage(this.options.local_storage);
|
|
572
592
|
}
|
|
573
593
|
});
|
|
594
|
+
*/
|
|
574
595
|
}
|
|
575
596
|
|
|
576
597
|
let container: HTMLElement | undefined;
|
|
@@ -2206,19 +2227,29 @@ export class EmbeddedSpreadsheet {
|
|
|
2206
2227
|
* @param formula - annotation formula. For charts, the chart formula.
|
|
2207
2228
|
* @param type - annotation type. Defaults to `treb-chart`.
|
|
2208
2229
|
* @param rect - coordinates, or a range reference for layout.
|
|
2209
|
-
*
|
|
2210
|
-
*
|
|
2211
|
-
*
|
|
2230
|
+
* @param options - evaluate options. because this function used to take
|
|
2231
|
+
* the argument separator, we allow that to be passed directly, but this
|
|
2232
|
+
* is deprecated. new code should use the options object.
|
|
2212
2233
|
*/
|
|
2213
|
-
public InsertAnnotation(formula: string, type: AnnotationType = 'treb-chart', rect?: IRectangle|RangeReference,
|
|
2234
|
+
public InsertAnnotation(formula: string, type: AnnotationType = 'treb-chart', rect?: IRectangle|RangeReference, options?: EvaluateOptions|','|';'): void {
|
|
2214
2235
|
|
|
2215
2236
|
let target: IRectangle | Partial<Area> | undefined;
|
|
2237
|
+
let argument_separator: ','|';'|undefined = undefined;
|
|
2238
|
+
let r1c1 = false;
|
|
2239
|
+
|
|
2240
|
+
if (typeof options === 'object') {
|
|
2241
|
+
argument_separator = options.argument_separator;
|
|
2242
|
+
r1c1 = !!options.r1c1;
|
|
2243
|
+
}
|
|
2244
|
+
else if (options === ',' || options === ';') {
|
|
2245
|
+
argument_separator = options;
|
|
2246
|
+
}
|
|
2216
2247
|
|
|
2217
2248
|
if (rect) {
|
|
2218
2249
|
target = Rectangle.IsRectangle(rect) ? rect : this.model.ResolveArea(rect, this.grid.active_sheet);
|
|
2219
2250
|
}
|
|
2220
2251
|
|
|
2221
|
-
if (argument_separator && argument_separator !== this.parser.argument_separator) {
|
|
2252
|
+
if (argument_separator && argument_separator !== this.parser.argument_separator || r1c1) {
|
|
2222
2253
|
const current = {
|
|
2223
2254
|
argument_separator: this.parser.argument_separator,
|
|
2224
2255
|
decimal_mark: this.parser.decimal_mark,
|
|
@@ -2233,11 +2264,17 @@ export class EmbeddedSpreadsheet {
|
|
|
2233
2264
|
this.parser.decimal_mark = DecimalMarkType.Comma;
|
|
2234
2265
|
}
|
|
2235
2266
|
|
|
2267
|
+
const r1c1_state = this.parser.flags.r1c1;
|
|
2268
|
+
if (r1c1) {
|
|
2269
|
+
this.parser.flags.r1c1 = r1c1;
|
|
2270
|
+
}
|
|
2271
|
+
|
|
2236
2272
|
const result = this.parser.Parse(formula);
|
|
2237
2273
|
|
|
2238
2274
|
// reset
|
|
2239
2275
|
this.parser.argument_separator = current.argument_separator;
|
|
2240
2276
|
this.parser.decimal_mark = current.decimal_mark;
|
|
2277
|
+
this.parser.flags.r1c1 = r1c1_state;
|
|
2241
2278
|
|
|
2242
2279
|
if (result.expression) {
|
|
2243
2280
|
formula = '=' + this.parser.Render(result.expression, { missing: '' });
|
|
@@ -3106,14 +3143,6 @@ export class EmbeddedSpreadsheet {
|
|
|
3106
3143
|
|
|
3107
3144
|
if (text && filename) {
|
|
3108
3145
|
const blob = new Blob([text as any], { type: 'text/plain;charset=utf-8' });
|
|
3109
|
-
/*
|
|
3110
|
-
// FileSaver.saveAs(blob, filename, { autoBom: false });
|
|
3111
|
-
const a = document.createElement('a');
|
|
3112
|
-
a.href = URL.createObjectURL(blob);
|
|
3113
|
-
a.download = filename;
|
|
3114
|
-
a.click();
|
|
3115
|
-
URL.revokeObjectURL(a.href);
|
|
3116
|
-
*/
|
|
3117
3146
|
this.SaveAs(blob, filename);
|
|
3118
3147
|
}
|
|
3119
3148
|
|
|
@@ -4312,7 +4341,7 @@ export class EmbeddedSpreadsheet {
|
|
|
4312
4341
|
*/
|
|
4313
4342
|
protected SaveAs(blob: Blob, filename: string) {
|
|
4314
4343
|
|
|
4315
|
-
const a =
|
|
4344
|
+
const a = DOMUtilities.Create('a');
|
|
4316
4345
|
a.href = URL.createObjectURL(blob);
|
|
4317
4346
|
a.download = filename;
|
|
4318
4347
|
a.click();
|
|
@@ -4437,7 +4466,7 @@ export class EmbeddedSpreadsheet {
|
|
|
4437
4466
|
return;
|
|
4438
4467
|
}
|
|
4439
4468
|
|
|
4440
|
-
const a =
|
|
4469
|
+
const a = DOMUtilities.Create('a');
|
|
4441
4470
|
a.setAttribute('target', this.options.hyperlinks);
|
|
4442
4471
|
a.setAttribute('href', data);
|
|
4443
4472
|
a.setAttribute('noreferrer', 'true');
|
|
@@ -4578,7 +4607,7 @@ export class EmbeddedSpreadsheet {
|
|
|
4578
4607
|
protected SelectFile2(accept: string, operation: FileChooserOperation) {
|
|
4579
4608
|
|
|
4580
4609
|
if (!this.file_chooser) {
|
|
4581
|
-
this.file_chooser =
|
|
4610
|
+
this.file_chooser = DOMUtilities.Create('input');
|
|
4582
4611
|
this.file_chooser.type = 'file';
|
|
4583
4612
|
|
|
4584
4613
|
const file_chooser = this.file_chooser;
|
|
@@ -4611,79 +4640,6 @@ export class EmbeddedSpreadsheet {
|
|
|
4611
4640
|
|
|
4612
4641
|
}
|
|
4613
4642
|
|
|
4614
|
-
/* *
|
|
4615
|
-
* show file chooser and resolve with the selected file, or undefined
|
|
4616
|
-
* /
|
|
4617
|
-
protected SelectFile(accept?: string): Promise<File | undefined> {
|
|
4618
|
-
|
|
4619
|
-
return new Promise((resolve) => {
|
|
4620
|
-
|
|
4621
|
-
const file_chooser = document.createElement('input');
|
|
4622
|
-
file_chooser.type = 'file';
|
|
4623
|
-
|
|
4624
|
-
if (accept) {
|
|
4625
|
-
file_chooser.accept = accept;
|
|
4626
|
-
}
|
|
4627
|
-
|
|
4628
|
-
// so the thing here is there is no way to trap a "cancel" event
|
|
4629
|
-
// from the file chooser. if you are waiting on a promise, that will
|
|
4630
|
-
// just get orphaned forever.
|
|
4631
|
-
|
|
4632
|
-
// it's not the end of the world, really, to leave a few of these
|
|
4633
|
-
// dangling, but this should allow it to clean up.
|
|
4634
|
-
|
|
4635
|
-
// the concept is that since file chooser is modal, there will never
|
|
4636
|
-
// be a focus event until the modal is closed. unfortunately the focus
|
|
4637
|
-
// event comes _before_ any input or change event from the file input,
|
|
4638
|
-
// so we have to wait.
|
|
4639
|
-
|
|
4640
|
-
// tested Cr, FF, IE11
|
|
4641
|
-
// update: works in Safari, although oddly not if you call the API
|
|
4642
|
-
// function from the console. not sure if that's a browserstack thing.
|
|
4643
|
-
|
|
4644
|
-
// eslint-disable-next-line prefer-const
|
|
4645
|
-
let finalize: (file?: File) => void;
|
|
4646
|
-
let timeout: NodeJS.Timeout|undefined;
|
|
4647
|
-
|
|
4648
|
-
// if you get a focus event, allow some reasonable time for the
|
|
4649
|
-
// corresponding change event. realistically this should be immediate,
|
|
4650
|
-
// but as long as there's not a lot of logic waiting on a cancel, it
|
|
4651
|
-
// doesn't really matter.
|
|
4652
|
-
|
|
4653
|
-
const window_focus = () => {
|
|
4654
|
-
|
|
4655
|
-
// prevent this from accidentally being called more than once
|
|
4656
|
-
window.removeEventListener('focus', window_focus);
|
|
4657
|
-
timeout = setTimeout(finalize, 250);
|
|
4658
|
-
}
|
|
4659
|
-
|
|
4660
|
-
const change_handler = () => {
|
|
4661
|
-
if (timeout) {
|
|
4662
|
-
clearTimeout(timeout);
|
|
4663
|
-
timeout = undefined; // necessary?
|
|
4664
|
-
}
|
|
4665
|
-
finalize(file_chooser.files ? file_chooser.files[0] : undefined);
|
|
4666
|
-
}
|
|
4667
|
-
|
|
4668
|
-
// our finalize method cleans up and resolves
|
|
4669
|
-
|
|
4670
|
-
finalize = (file?: File) => {
|
|
4671
|
-
file_chooser.removeEventListener('change', change_handler);
|
|
4672
|
-
window.removeEventListener('focus', window_focus);
|
|
4673
|
-
resolve(file);
|
|
4674
|
-
};
|
|
4675
|
-
|
|
4676
|
-
file_chooser.addEventListener('change', change_handler);
|
|
4677
|
-
window.addEventListener('focus', window_focus);
|
|
4678
|
-
|
|
4679
|
-
file_chooser.click();
|
|
4680
|
-
|
|
4681
|
-
|
|
4682
|
-
});
|
|
4683
|
-
|
|
4684
|
-
}
|
|
4685
|
-
*/
|
|
4686
|
-
|
|
4687
4643
|
/**
|
|
4688
4644
|
* Insert an image. This method will open a file chooser and (if an image
|
|
4689
4645
|
* is selected) insert the image into the document.
|
|
@@ -4728,7 +4684,7 @@ export class EmbeddedSpreadsheet {
|
|
|
4728
4684
|
}
|
|
4729
4685
|
}
|
|
4730
4686
|
|
|
4731
|
-
const img =
|
|
4687
|
+
const img = DOMUtilities.Create('img');
|
|
4732
4688
|
img.src = contents;
|
|
4733
4689
|
|
|
4734
4690
|
// this is to let the browser figure out the image size.
|
|
@@ -5093,7 +5049,7 @@ export class EmbeddedSpreadsheet {
|
|
|
5093
5049
|
const reference = ValidateURI(annotation.data.data.src);
|
|
5094
5050
|
if (reference) {
|
|
5095
5051
|
|
|
5096
|
-
const img =
|
|
5052
|
+
const img = DOMUtilities.Create('img');
|
|
5097
5053
|
img.src = reference;
|
|
5098
5054
|
|
|
5099
5055
|
if (annotation.data.data.scale === 'fixed') {
|
|
@@ -5142,9 +5098,27 @@ export class EmbeddedSpreadsheet {
|
|
|
5142
5098
|
|
|
5143
5099
|
// console.info(json);
|
|
5144
5100
|
|
|
5101
|
+
// why are we saving this here? and should we not route
|
|
5102
|
+
// through the method? I guess the question should be, is
|
|
5103
|
+
// the visibilitychange handler not sufficient to save the
|
|
5104
|
+
// file? (...)
|
|
5105
|
+
|
|
5106
|
+
// I would prefer to just save once, on visibilitychange -> hidden.
|
|
5107
|
+
// the problem is that this method gets called on "data" events,
|
|
5108
|
+
// which should not trigger saving. we could check the flag?
|
|
5109
|
+
|
|
5110
|
+
// if this does come back, (1) use a method -- maybe split the
|
|
5111
|
+
// SaveLocalStorage method in two, and call the inner half (because
|
|
5112
|
+
// we've already serialized); and (2) gate on dirty.
|
|
5113
|
+
|
|
5114
|
+
// but for the time being we're removing it.
|
|
5115
|
+
|
|
5116
|
+
/*
|
|
5145
5117
|
if (this.options.local_storage) {
|
|
5146
5118
|
localStorage.setItem(this.options.local_storage, json);
|
|
5147
5119
|
}
|
|
5120
|
+
*/
|
|
5121
|
+
|
|
5148
5122
|
if (this.options.undo) {
|
|
5149
5123
|
this.PushUndo(json, undo_selection, false);
|
|
5150
5124
|
}
|
|
@@ -19,16 +19,16 @@
|
|
|
19
19
|
*
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
+
import { DOMUtilities } from 'treb-base-types';
|
|
23
|
+
|
|
22
24
|
export class Spinner {
|
|
23
25
|
|
|
24
26
|
private node: HTMLDivElement;
|
|
25
27
|
private visible = false;
|
|
26
28
|
|
|
27
29
|
constructor(public container: HTMLElement) {
|
|
28
|
-
this.node =
|
|
29
|
-
this.node.classList.add('treb-spinner');
|
|
30
|
+
this.node = DOMUtilities.Div('treb-spinner', container);
|
|
30
31
|
this.node.innerHTML = `<div><div></div><div></div><div></div><div></div></div>`;
|
|
31
|
-
container.appendChild(this.node);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
public Show(): void {
|
|
@@ -90,6 +90,15 @@
|
|
|
90
90
|
white-space: nowrap;
|
|
91
91
|
position: relative;
|
|
92
92
|
// -webkit-user-modify: read-write;
|
|
93
|
+
|
|
94
|
+
// this fixes the firefox issue (firefox removing spaces), but
|
|
95
|
+
// I'm not sure if it will cause other problems. for the overlay
|
|
96
|
+
// editor we're trapping CR, so it shouldn't be a typing problem --
|
|
97
|
+
// it might be an issue on paste though. also need to check safari
|
|
98
|
+
// with pre here.
|
|
99
|
+
|
|
100
|
+
white-space: pre;
|
|
101
|
+
|
|
93
102
|
}
|
|
94
103
|
|
|
95
104
|
/** fix for firefox layout bug */
|
|
@@ -169,7 +169,11 @@ export class Chart {
|
|
|
169
169
|
}
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
-
|
|
172
|
+
// "accent7" will break
|
|
173
|
+
|
|
174
|
+
if (i < 6) {
|
|
175
|
+
series['c:spPr']['a:ln']['a:solidFill']['a:schemeClr'].a$['val'] = `accent${i+1}`;
|
|
176
|
+
}
|
|
173
177
|
|
|
174
178
|
series['c:yVal']['c:numRef']['c:f'] = this.options.data[i]?.label;
|
|
175
179
|
|
|
@@ -255,7 +259,12 @@ export class Chart {
|
|
|
255
259
|
|
|
256
260
|
series['c:idx'] = { a$: { val: i.toString() }};
|
|
257
261
|
series['c:order'] = { a$: { val: i.toString() }};
|
|
258
|
-
|
|
262
|
+
|
|
263
|
+
// "accent7" will break
|
|
264
|
+
|
|
265
|
+
if (i < 6) {
|
|
266
|
+
series['c:spPr']['a:solidFill']['a:schemeClr'].a$['val'] = `accent${i+1}`;
|
|
267
|
+
}
|
|
259
268
|
|
|
260
269
|
if (!i && this.options.labels) {
|
|
261
270
|
series['c:cat'] = {
|
|
@@ -642,6 +642,9 @@ export class Exporter {
|
|
|
642
642
|
// is this backwards, vis a vis our rendering? I think it might be...
|
|
643
643
|
// YES: should be row pattern -> row -> column -> cell [corrected]
|
|
644
644
|
|
|
645
|
+
// FIXME: can't we just ask the sheet? (A: no, because we don't have
|
|
646
|
+
// an actual sheet, although we could?)
|
|
647
|
+
|
|
645
648
|
// if (sheet.row_style && sheet.row_style[row]) {
|
|
646
649
|
// list.push(sheet.row_style[row]);
|
|
647
650
|
// }
|
|
@@ -1270,6 +1273,7 @@ export class Exporter {
|
|
|
1270
1273
|
},
|
|
1271
1274
|
dataValidations: {},
|
|
1272
1275
|
hyperlinks: {},
|
|
1276
|
+
conditionalFormatting: {},
|
|
1273
1277
|
pageMargins: {
|
|
1274
1278
|
a$: {
|
|
1275
1279
|
left: 0.7,
|
|
@@ -2157,7 +2161,13 @@ export class Exporter {
|
|
|
2157
2161
|
if (conditionalFormatting.length) {
|
|
2158
2162
|
dom.worksheet.conditionalFormatting = (conditionalFormatting.length > 1) ? conditionalFormatting : conditionalFormatting[0];
|
|
2159
2163
|
}
|
|
2160
|
-
|
|
2164
|
+
else {
|
|
2165
|
+
delete dom.worksheet.conditionalFormatting;
|
|
2166
|
+
}
|
|
2167
|
+
|
|
2168
|
+
}
|
|
2169
|
+
else {
|
|
2170
|
+
delete dom.worksheet.conditionalFormatting;
|
|
2161
2171
|
}
|
|
2162
2172
|
|
|
2163
2173
|
// --- merges ------------------------------------------------------------
|
|
@@ -2333,9 +2343,9 @@ export class Exporter {
|
|
|
2333
2343
|
|
|
2334
2344
|
// --- move page margins -------------------------------------------------
|
|
2335
2345
|
|
|
2336
|
-
const margins = dom.worksheet.pageMargins;
|
|
2337
|
-
delete dom.worksheet.pageMargins;
|
|
2338
|
-
dom.worksheet.pageMargins = margins;
|
|
2346
|
+
// const margins = dom.worksheet.pageMargins;
|
|
2347
|
+
// delete dom.worksheet.pageMargins;
|
|
2348
|
+
// dom.worksheet.pageMargins = margins;
|
|
2339
2349
|
|
|
2340
2350
|
// --- end? --------------------------------------------------------------
|
|
2341
2351
|
|
|
@@ -424,17 +424,18 @@ export class StyleCache {
|
|
|
424
424
|
fill.pattern_type = 'solid';
|
|
425
425
|
if (composite.fill.text) {
|
|
426
426
|
fill.fg_color = { argb: composite.fill.text };
|
|
427
|
+
options.fill = fill;
|
|
427
428
|
}
|
|
428
429
|
else if (typeof composite.fill.theme === 'number') {
|
|
429
430
|
fill.fg_color = { theme: composite.fill.theme };
|
|
430
431
|
if (composite.fill.tint) {
|
|
431
432
|
fill.fg_color.tint = composite.fill.tint;
|
|
432
433
|
}
|
|
434
|
+
options.fill = fill;
|
|
433
435
|
}
|
|
434
436
|
else {
|
|
435
|
-
fill.fg_color = { theme: 1 };
|
|
437
|
+
// fill.fg_color = { theme: 1 };
|
|
436
438
|
}
|
|
437
|
-
options.fill = fill;
|
|
438
439
|
}
|
|
439
440
|
|
|
440
441
|
if (composite.wrap) {
|