@trebco/treb 28.13.2 → 28.15.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/dist/treb-spreadsheet-light.mjs +9 -9
- package/dist/treb-spreadsheet.mjs +9 -9
- package/dist/treb.d.ts +19 -3
- package/package.json +1 -1
- package/treb-base-types/src/style.ts +3 -0
- package/treb-calculator/src/expression-calculator.ts +9 -5
- package/treb-calculator/src/functions/base-functions.ts +334 -57
- package/treb-embed/markup/layout.html +15 -10
- package/treb-embed/markup/toolbar.html +5 -5
- package/treb-embed/src/custom-element/spreadsheet-constructor.ts +38 -2
- package/treb-embed/src/embedded-spreadsheet.ts +66 -2
- package/treb-embed/src/options.ts +5 -0
- package/treb-embed/style/formula-bar.scss +20 -7
- package/treb-embed/style/theme-defaults.scss +20 -0
- package/treb-export/src/export2.ts +6 -1
- package/treb-export/src/import2.ts +67 -3
- package/treb-export/src/shared-strings2.ts +1 -1
- package/treb-export/src/workbook-style2.ts +11 -38
- package/treb-export/src/workbook2.ts +119 -1
- package/treb-grid/src/editors/formula_bar.ts +23 -1
- package/treb-grid/src/render/tile_renderer.ts +46 -3
- package/treb-grid/src/types/annotation.ts +17 -3
- package/treb-grid/src/types/grid.ts +8 -0
- package/treb-grid/src/types/grid_options.ts +3 -2
- package/treb-grid/src/types/named_range.ts +8 -1
|
@@ -13,6 +13,23 @@ import type { ToolbarMessage } from '../toolbar-message';
|
|
|
13
13
|
|
|
14
14
|
import { DOMContext } from 'treb-base-types';
|
|
15
15
|
|
|
16
|
+
/** with a view towards i18n */
|
|
17
|
+
const default_titles: Record<string, string> = {
|
|
18
|
+
|
|
19
|
+
close_dialog: 'Close dialog',
|
|
20
|
+
insert_function: 'Insert function...',
|
|
21
|
+
delete_sheet: 'Delete current sheet',
|
|
22
|
+
add_sheet: 'Add sheet',
|
|
23
|
+
document_modified: 'This document has been modified from the original version.',
|
|
24
|
+
recalculate: 'Recalculate',
|
|
25
|
+
toggle_toolbar: 'Toggle toolbar',
|
|
26
|
+
export: 'Export as XLSX',
|
|
27
|
+
revert: 'Revert to original version',
|
|
28
|
+
about: `What's this?`,
|
|
29
|
+
toggle_sidebar: 'Toggle sidebar',
|
|
30
|
+
|
|
31
|
+
};
|
|
32
|
+
|
|
16
33
|
/** @internal */
|
|
17
34
|
export class SpreadsheetConstructor<USER_DATA_TYPE = unknown> {
|
|
18
35
|
|
|
@@ -391,6 +408,7 @@ export class SpreadsheetConstructor<USER_DATA_TYPE = unknown> {
|
|
|
391
408
|
'revert': !!sheet.options.revert_button,
|
|
392
409
|
'toolbar': !!sheet.options.toolbar,
|
|
393
410
|
'export': !!sheet.options.export,
|
|
411
|
+
'insert-function': !!sheet.options.insert_function_button,
|
|
394
412
|
|
|
395
413
|
// the following won't work as expected in split, because this
|
|
396
414
|
// code won't be run when the new view is created -- do something
|
|
@@ -545,6 +563,24 @@ export class SpreadsheetConstructor<USER_DATA_TYPE = unknown> {
|
|
|
545
563
|
|
|
546
564
|
}
|
|
547
565
|
|
|
566
|
+
// --- titles --------------------------------------------------------------
|
|
567
|
+
|
|
568
|
+
const elements = Array.from(this.layout_element.querySelectorAll('[data-title]'));
|
|
569
|
+
for (const element of elements) {
|
|
570
|
+
if (element instanceof HTMLElement) {
|
|
571
|
+
|
|
572
|
+
// temp workaround
|
|
573
|
+
if (element.dataset.activeTitle) {
|
|
574
|
+
continue;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
if (element.dataset.title && default_titles[element.dataset.title]) {
|
|
578
|
+
element.title = default_titles[element.dataset.title];
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
548
584
|
// --- animated ------------------------------------------------------------
|
|
549
585
|
|
|
550
586
|
// requestAnimationFrame(() => {
|
|
@@ -580,8 +616,8 @@ export class SpreadsheetConstructor<USER_DATA_TYPE = unknown> {
|
|
|
580
616
|
if (value) {
|
|
581
617
|
// value.classList.remove('treb-active');
|
|
582
618
|
value.removeAttribute('active');
|
|
583
|
-
if (value.dataset.
|
|
584
|
-
value.title = value.dataset.
|
|
619
|
+
if (value.dataset.inactiveTitle) {
|
|
620
|
+
value.title = value.dataset.inactiveTitle;
|
|
585
621
|
}
|
|
586
622
|
}
|
|
587
623
|
}
|
|
@@ -723,8 +723,7 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
723
723
|
|
|
724
724
|
const grid_options: GridOptions = {
|
|
725
725
|
// expand: false,
|
|
726
|
-
|
|
727
|
-
insert_function_button: false, // do we have this?
|
|
726
|
+
// insert_function_button: false, // do we have this?
|
|
728
727
|
in_cell_editor: true, // if this is always true, why is it an option?
|
|
729
728
|
repaint_on_cell_change: false,
|
|
730
729
|
scrollbars: this.options.scrollbars,
|
|
@@ -2078,6 +2077,14 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
2078
2077
|
for (const format of sheet.conditional_formats) {
|
|
2079
2078
|
format.internal = undefined;
|
|
2080
2079
|
}
|
|
2080
|
+
for (const annotation of sheet.annotations) {
|
|
2081
|
+
if (annotation.view && annotation.data.type === 'textbox') {
|
|
2082
|
+
const view: AnnotationViewData = annotation.view[this.grid.view_index] || {};
|
|
2083
|
+
if (view.update_callback) {
|
|
2084
|
+
view.update_callback();
|
|
2085
|
+
}
|
|
2086
|
+
}
|
|
2087
|
+
}
|
|
2081
2088
|
}
|
|
2082
2089
|
|
|
2083
2090
|
this.calculator.UpdateConditionals();
|
|
@@ -5349,6 +5356,63 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
5349
5356
|
}
|
|
5350
5357
|
|
|
5351
5358
|
}
|
|
5359
|
+
else if (annotation.data.type === 'textbox') {
|
|
5360
|
+
|
|
5361
|
+
if (annotation.data.data) {
|
|
5362
|
+
const container = document.createElement('div');
|
|
5363
|
+
container.classList.add('treb-annotation-textbox');
|
|
5364
|
+
|
|
5365
|
+
for (const paragraph of annotation.data.data.paragraphs) {
|
|
5366
|
+
const p = document.createElement('p');
|
|
5367
|
+
if (paragraph.style) {
|
|
5368
|
+
if (paragraph.style.horizontal_align === 'right' ||
|
|
5369
|
+
paragraph.style.horizontal_align === 'center') {
|
|
5370
|
+
p.style.textAlign = paragraph.style.horizontal_align;
|
|
5371
|
+
}
|
|
5372
|
+
}
|
|
5373
|
+
|
|
5374
|
+
for (const entry of paragraph.content) {
|
|
5375
|
+
const span = document.createElement('span');
|
|
5376
|
+
span.textContent = entry.text || '';
|
|
5377
|
+
if (entry.style?.bold) {
|
|
5378
|
+
span.style.fontWeight = '600';
|
|
5379
|
+
}
|
|
5380
|
+
if (entry.style?.italic) {
|
|
5381
|
+
span.style.fontStyle = 'italic';
|
|
5382
|
+
}
|
|
5383
|
+
p.appendChild(span);
|
|
5384
|
+
}
|
|
5385
|
+
container.append(p);
|
|
5386
|
+
}
|
|
5387
|
+
|
|
5388
|
+
view.content_node.append(container);
|
|
5389
|
+
|
|
5390
|
+
if (annotation.data.data.style) {
|
|
5391
|
+
|
|
5392
|
+
const style = annotation.data.data.style;
|
|
5393
|
+
const update_textbox = () => {
|
|
5394
|
+
|
|
5395
|
+
if (style.fill) {
|
|
5396
|
+
const color = ThemeColor2(this.grid.theme, style.fill);
|
|
5397
|
+
container.style.background = color;
|
|
5398
|
+
}
|
|
5399
|
+
|
|
5400
|
+
};
|
|
5401
|
+
|
|
5402
|
+
view.update_callback = () => {
|
|
5403
|
+
if (!this.grid.headless) {
|
|
5404
|
+
update_textbox();
|
|
5405
|
+
}
|
|
5406
|
+
};
|
|
5407
|
+
|
|
5408
|
+
update_textbox();
|
|
5409
|
+
|
|
5410
|
+
}
|
|
5411
|
+
|
|
5412
|
+
}
|
|
5413
|
+
|
|
5414
|
+
}
|
|
5415
|
+
|
|
5352
5416
|
}
|
|
5353
5417
|
}
|
|
5354
5418
|
|
|
@@ -25,11 +25,10 @@
|
|
|
25
25
|
|
|
26
26
|
grid-area: 1/1/2/2;
|
|
27
27
|
|
|
28
|
-
// min-height: 3em; // FIXME
|
|
29
|
-
|
|
30
28
|
display: flex;
|
|
31
29
|
flex-direction: row;
|
|
32
30
|
text-align: left;
|
|
31
|
+
gap: .5em;
|
|
33
32
|
|
|
34
33
|
&[hidden] {
|
|
35
34
|
display: none;
|
|
@@ -39,7 +38,6 @@
|
|
|
39
38
|
|
|
40
39
|
max-width: 100%;
|
|
41
40
|
overflow-x: hidden;
|
|
42
|
-
/* last ditch for IE11 */
|
|
43
41
|
|
|
44
42
|
/** label for selection address */
|
|
45
43
|
.treb-address-label {
|
|
@@ -56,7 +54,7 @@
|
|
|
56
54
|
justify-content: center;
|
|
57
55
|
padding-left: 3px;
|
|
58
56
|
|
|
59
|
-
margin-right: 6px;
|
|
57
|
+
// margin-right: 6px;
|
|
60
58
|
|
|
61
59
|
&>div {
|
|
62
60
|
outline: none;
|
|
@@ -66,6 +64,20 @@
|
|
|
66
64
|
}
|
|
67
65
|
}
|
|
68
66
|
|
|
67
|
+
.treb-insert-function-button {
|
|
68
|
+
min-height: 1.5em;
|
|
69
|
+
height: 1.75em;
|
|
70
|
+
border: 1px solid var(--treb-formula-bar-border-color, var(--treb-ui-border-color, #ccc));
|
|
71
|
+
border-radius: 2px;
|
|
72
|
+
background: transparent;
|
|
73
|
+
|
|
74
|
+
&[hidden] {
|
|
75
|
+
display: none;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** expand formula box -- caret/arrow */
|
|
69
81
|
.expand-button {
|
|
70
82
|
background: transparent;
|
|
71
83
|
border: 0;
|
|
@@ -160,7 +172,7 @@
|
|
|
160
172
|
|
|
161
173
|
}
|
|
162
174
|
|
|
163
|
-
|
|
175
|
+
/* * f(x) button, optional * /
|
|
164
176
|
.formula-button {
|
|
165
177
|
border: 1px solid #ccc;
|
|
166
178
|
border-radius: 2px;
|
|
@@ -188,8 +200,9 @@
|
|
|
188
200
|
}
|
|
189
201
|
|
|
190
202
|
}
|
|
191
|
-
|
|
203
|
+
*/
|
|
204
|
+
|
|
192
205
|
|
|
193
|
-
|
|
206
|
+
}
|
|
194
207
|
|
|
195
208
|
}
|
|
@@ -519,4 +519,24 @@ $text-reference-color-5: rgb(254, 47, 1);
|
|
|
519
519
|
font-family: var(--treb-grid-font-family-osx, var(--treb-grid-font-family, inherit));
|
|
520
520
|
}
|
|
521
521
|
|
|
522
|
+
/**
|
|
523
|
+
*
|
|
524
|
+
*/
|
|
525
|
+
.treb-annotation-textbox {
|
|
526
|
+
background: Canvas;
|
|
527
|
+
position: relative;
|
|
528
|
+
top: 0px;
|
|
529
|
+
left: 0px;
|
|
530
|
+
overflow: hidden;
|
|
531
|
+
width: 100%;
|
|
532
|
+
height: 100%;
|
|
533
|
+
padding: .5em; // ?
|
|
534
|
+
|
|
535
|
+
p {
|
|
536
|
+
margin-block-start: 0;
|
|
537
|
+
margin-block-end: 0;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
}
|
|
541
|
+
|
|
522
542
|
}
|
|
@@ -224,9 +224,10 @@ export class Exporter {
|
|
|
224
224
|
},
|
|
225
225
|
};
|
|
226
226
|
|
|
227
|
-
if (xf.horizontal_alignment || xf.vertical_alignment || xf.wrap_text) {
|
|
227
|
+
if (xf.horizontal_alignment || xf.vertical_alignment || xf.wrap_text || xf.indent) {
|
|
228
228
|
// block.a$.applyAlignment = 1;
|
|
229
229
|
block.alignment = { a$: {}};
|
|
230
|
+
|
|
230
231
|
if (xf.horizontal_alignment) {
|
|
231
232
|
block.alignment.a$.horizontal = xf.horizontal_alignment;
|
|
232
233
|
}
|
|
@@ -236,6 +237,10 @@ export class Exporter {
|
|
|
236
237
|
if (xf.wrap_text) {
|
|
237
238
|
block.alignment.a$.wrapText = 1;
|
|
238
239
|
}
|
|
240
|
+
if (xf.indent && xf.horizontal_alignment !== 'center') {
|
|
241
|
+
block.alignment.a$.indent = xf.indent;
|
|
242
|
+
}
|
|
243
|
+
|
|
239
244
|
}
|
|
240
245
|
|
|
241
246
|
return block;
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
import UZip from 'uzip';
|
|
25
25
|
import Base64JS from 'base64-js';
|
|
26
26
|
|
|
27
|
-
import type { AnchoredChartDescription, AnchoredImageDescription} from './workbook2';
|
|
27
|
+
import type { AnchoredChartDescription, AnchoredImageDescription, AnchoredTextBoxDescription} from './workbook2';
|
|
28
28
|
import { ChartType, ConditionalFormatOperators, Workbook } from './workbook2';
|
|
29
29
|
import type { ParseResult } from 'treb-parser';
|
|
30
30
|
import { Parser } from 'treb-parser';
|
|
@@ -170,8 +170,13 @@ export class Importer {
|
|
|
170
170
|
const parse_result = this.parser.Parse(formula); // l10n?
|
|
171
171
|
if (parse_result.expression) {
|
|
172
172
|
this.parser.Walk(parse_result.expression, (unit) => {
|
|
173
|
-
if (unit.type === 'call'
|
|
174
|
-
|
|
173
|
+
if (unit.type === 'call') {
|
|
174
|
+
if (/^_xll\./.test(unit.name)) {
|
|
175
|
+
unit.name = unit.name.substring(5);
|
|
176
|
+
}
|
|
177
|
+
else if (/^_xlfn\./.test(unit.name)) {
|
|
178
|
+
unit.name = unit.name.substring(6);
|
|
179
|
+
}
|
|
175
180
|
}
|
|
176
181
|
return true;
|
|
177
182
|
});
|
|
@@ -390,6 +395,20 @@ export class Importer {
|
|
|
390
395
|
|
|
391
396
|
case 'expression':
|
|
392
397
|
if (rule.formula) {
|
|
398
|
+
|
|
399
|
+
if (typeof rule.formula !== 'string') {
|
|
400
|
+
console.info("conditional expression", {rule});
|
|
401
|
+
if (rule.formula.t$) {
|
|
402
|
+
|
|
403
|
+
// the only case (to date) we've seen here is that the attribute
|
|
404
|
+
// is "xml:space=preserve", which we can ignore (are you sure?)
|
|
405
|
+
// (should we check that?)
|
|
406
|
+
|
|
407
|
+
rule.formula = rule.formula.t$;
|
|
408
|
+
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
393
412
|
let style = {};
|
|
394
413
|
|
|
395
414
|
if (rule.a$.dxfId) {
|
|
@@ -498,6 +517,26 @@ export class Importer {
|
|
|
498
517
|
const conditional_formatting = FindAll('worksheet/conditionalFormatting');
|
|
499
518
|
for (const element of conditional_formatting) {
|
|
500
519
|
if (element.a$?.sqref ){
|
|
520
|
+
|
|
521
|
+
// FIXME: this attribute might include multiple ranges? e.g.:
|
|
522
|
+
//
|
|
523
|
+
// <conditionalFormatting sqref="B31:I31 B10:E30 G10:I30 F14:F15">
|
|
524
|
+
|
|
525
|
+
const parts = element.a$.sqref.split(/\s+/);
|
|
526
|
+
for (const part of parts) {
|
|
527
|
+
const area = sheet.TranslateAddress(part);
|
|
528
|
+
if (element.cfRule) {
|
|
529
|
+
const rules = Array.isArray(element.cfRule) ? element.cfRule : [element.cfRule];
|
|
530
|
+
for (const rule of rules) {
|
|
531
|
+
const format = this.ParseConditionalFormat(area, rule);
|
|
532
|
+
if (format) {
|
|
533
|
+
conditional_formats.push(format);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/*
|
|
501
540
|
const area = sheet.TranslateAddress(element.a$.sqref);
|
|
502
541
|
if (element.cfRule) {
|
|
503
542
|
const rules = Array.isArray(element.cfRule) ? element.cfRule : [element.cfRule];
|
|
@@ -508,6 +547,7 @@ export class Importer {
|
|
|
508
547
|
}
|
|
509
548
|
}
|
|
510
549
|
}
|
|
550
|
+
*/
|
|
511
551
|
}
|
|
512
552
|
}
|
|
513
553
|
|
|
@@ -808,6 +848,7 @@ export class Importer {
|
|
|
808
848
|
const drawings = FindAll('worksheet/drawing');
|
|
809
849
|
const chart_descriptors: AnchoredChartDescription[] = [];
|
|
810
850
|
const image_descriptors: AnchoredImageDescription[] = [];
|
|
851
|
+
const textbox_descriptors: AnchoredTextBoxDescription[] = [];
|
|
811
852
|
|
|
812
853
|
for (const child of drawings) {
|
|
813
854
|
|
|
@@ -832,6 +873,9 @@ export class Importer {
|
|
|
832
873
|
case 'image':
|
|
833
874
|
image_descriptors.push(entry);
|
|
834
875
|
break;
|
|
876
|
+
case 'textbox':
|
|
877
|
+
textbox_descriptors.push(entry);
|
|
878
|
+
break;
|
|
835
879
|
}
|
|
836
880
|
}
|
|
837
881
|
}
|
|
@@ -873,6 +917,26 @@ export class Importer {
|
|
|
873
917
|
|
|
874
918
|
};
|
|
875
919
|
|
|
920
|
+
for (const descriptor of textbox_descriptors) {
|
|
921
|
+
|
|
922
|
+
const layout: AnnotationLayout = {
|
|
923
|
+
tl: AnchorToCorner(descriptor.anchor.from),
|
|
924
|
+
br: AnchorToCorner(descriptor.anchor.to),
|
|
925
|
+
};
|
|
926
|
+
|
|
927
|
+
// console.info({descriptor});
|
|
928
|
+
|
|
929
|
+
annotations.push({
|
|
930
|
+
layout,
|
|
931
|
+
type: 'textbox',
|
|
932
|
+
data: {
|
|
933
|
+
style: descriptor.style,
|
|
934
|
+
paragraphs: descriptor.paragraphs,
|
|
935
|
+
}
|
|
936
|
+
});
|
|
937
|
+
|
|
938
|
+
}
|
|
939
|
+
|
|
876
940
|
for (const descriptor of image_descriptors) {
|
|
877
941
|
if (descriptor && descriptor.image) {
|
|
878
942
|
|
|
@@ -44,7 +44,7 @@ export class SharedStrings {
|
|
|
44
44
|
// <t>text here!</t>
|
|
45
45
|
// </si>
|
|
46
46
|
|
|
47
|
-
if (si.t) {
|
|
47
|
+
if (si.t !== undefined) {
|
|
48
48
|
|
|
49
49
|
// seen recently in the wild, text with leading (or trailing) spaces
|
|
50
50
|
// has an attribute xml:space=preserve (which makes sense, but was not
|
|
@@ -76,6 +76,7 @@ export interface CellXf {
|
|
|
76
76
|
horizontal_alignment?: string;
|
|
77
77
|
vertical_alignment?: string;
|
|
78
78
|
xfid?: number;
|
|
79
|
+
indent?: number;
|
|
79
80
|
|
|
80
81
|
// FIXME // apply_font?: boolean;
|
|
81
82
|
// FIXME // apply_border?: boolean;
|
|
@@ -157,6 +158,7 @@ export interface StyleOptions {
|
|
|
157
158
|
vertical_alignment?: string;
|
|
158
159
|
wrap?: boolean;
|
|
159
160
|
fill?: Fill;
|
|
161
|
+
indent?: number;
|
|
160
162
|
}
|
|
161
163
|
|
|
162
164
|
|
|
@@ -434,6 +436,8 @@ export class StyleCache {
|
|
|
434
436
|
break;
|
|
435
437
|
}
|
|
436
438
|
|
|
439
|
+
options.indent = composite.indent;
|
|
440
|
+
|
|
437
441
|
if (composite.fill) {
|
|
438
442
|
fill.pattern_type = 'solid';
|
|
439
443
|
if (composite.fill.text) {
|
|
@@ -663,6 +667,10 @@ export class StyleCache {
|
|
|
663
667
|
break;
|
|
664
668
|
}
|
|
665
669
|
|
|
670
|
+
// indent
|
|
671
|
+
|
|
672
|
+
props.indent = xf.indent;
|
|
673
|
+
|
|
666
674
|
// wrap
|
|
667
675
|
|
|
668
676
|
if (xf.wrap_text) {
|
|
@@ -1091,6 +1099,7 @@ export class StyleCache {
|
|
|
1091
1099
|
xf.border === border_index &&
|
|
1092
1100
|
xf.number_format === number_format_index &&
|
|
1093
1101
|
!!xf.wrap_text === !!options.wrap &&
|
|
1102
|
+
xf.indent === options.indent &&
|
|
1094
1103
|
((!options.horizontal_alignment && !xf.horizontal_alignment) || options.horizontal_alignment === xf.horizontal_alignment) &&
|
|
1095
1104
|
((!options.vertical_alignment && !xf.vertical_alignment) || options.vertical_alignment === xf.vertical_alignment)) {
|
|
1096
1105
|
|
|
@@ -1106,6 +1115,7 @@ export class StyleCache {
|
|
|
1106
1115
|
fill: fill_index,
|
|
1107
1116
|
border: border_index,
|
|
1108
1117
|
number_format: number_format_index,
|
|
1118
|
+
indent: options.indent,
|
|
1109
1119
|
};
|
|
1110
1120
|
|
|
1111
1121
|
if (options.horizontal_alignment) {
|
|
@@ -1120,44 +1130,6 @@ export class StyleCache {
|
|
|
1120
1130
|
|
|
1121
1131
|
this.cell_xfs.push(new_xf);
|
|
1122
1132
|
|
|
1123
|
-
/*
|
|
1124
|
-
|
|
1125
|
-
// add the node structure
|
|
1126
|
-
|
|
1127
|
-
if (!this.dom) throw new Error('missing dom');
|
|
1128
|
-
const xfs = this.dom.find('./cellXfs');
|
|
1129
|
-
|
|
1130
|
-
if (!xfs) throw new Error('xfs not found');
|
|
1131
|
-
xfs.attrib.count = (Number(xfs.attrib.count || 0) + 1).toString();
|
|
1132
|
-
|
|
1133
|
-
const new_element = Element('xf', {
|
|
1134
|
-
borderId: new_xf.border.toString(),
|
|
1135
|
-
fillId: new_xf.fill.toString(),
|
|
1136
|
-
fontId: new_xf.font.toString(),
|
|
1137
|
-
numFmtId: new_xf.number_format.toString(),
|
|
1138
|
-
});
|
|
1139
|
-
|
|
1140
|
-
if (new_xf.horizontal_alignment || new_xf.vertical_alignment) {
|
|
1141
|
-
const attrs: {[index: string]: string} = {};
|
|
1142
|
-
if (new_xf.horizontal_alignment) {
|
|
1143
|
-
attrs.horizontal = new_xf.horizontal_alignment;
|
|
1144
|
-
}
|
|
1145
|
-
if (new_xf.vertical_alignment) {
|
|
1146
|
-
attrs.vertical = new_xf.vertical_alignment;
|
|
1147
|
-
}
|
|
1148
|
-
if (new_xf.wrap_text) {
|
|
1149
|
-
attrs.wrapText = '1';
|
|
1150
|
-
}
|
|
1151
|
-
new_element.append(Element('alignment', attrs));
|
|
1152
|
-
}
|
|
1153
|
-
|
|
1154
|
-
if (typeof new_xf.xfid !== 'undefined') {
|
|
1155
|
-
new_element.attrib.xfId = new_xf.xfid.toString();
|
|
1156
|
-
}
|
|
1157
|
-
|
|
1158
|
-
xfs.append(new_element);
|
|
1159
|
-
*/
|
|
1160
|
-
|
|
1161
1133
|
return this.cell_xfs.length - 1;
|
|
1162
1134
|
|
|
1163
1135
|
}
|
|
@@ -1255,6 +1227,7 @@ export class StyleCache {
|
|
|
1255
1227
|
xf.horizontal_alignment = element.alignment.a$.horizontal;
|
|
1256
1228
|
xf.vertical_alignment = element.alignment.a$.vertical;
|
|
1257
1229
|
xf.wrap_text = !!element.alignment.a$.wrapText;
|
|
1230
|
+
xf.indent = element.alignment.a$.indent || undefined;
|
|
1258
1231
|
}
|
|
1259
1232
|
|
|
1260
1233
|
return xf;
|
|
@@ -44,6 +44,7 @@ import { Theme } from './workbook-theme2';
|
|
|
44
44
|
import { Sheet, VisibleState } from './workbook-sheet2';
|
|
45
45
|
import type { RelationshipMap } from './relationship';
|
|
46
46
|
import { ZipWrapper } from './zip-wrapper';
|
|
47
|
+
import type { CellStyle } from 'treb-base-types';
|
|
47
48
|
|
|
48
49
|
|
|
49
50
|
/*
|
|
@@ -98,7 +99,23 @@ export interface AnchoredChartDescription {
|
|
|
98
99
|
anchor: TwoCellAnchor,
|
|
99
100
|
}
|
|
100
101
|
|
|
101
|
-
export
|
|
102
|
+
export interface AnchoredTextBoxDescription {
|
|
103
|
+
type: 'textbox';
|
|
104
|
+
style?: CellStyle;
|
|
105
|
+
paragraphs: {
|
|
106
|
+
style?: CellStyle,
|
|
107
|
+
content: {
|
|
108
|
+
text: string,
|
|
109
|
+
style?: CellStyle
|
|
110
|
+
}[],
|
|
111
|
+
}[];
|
|
112
|
+
anchor: TwoCellAnchor,
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export type AnchoredDrawingPart =
|
|
116
|
+
AnchoredChartDescription |
|
|
117
|
+
AnchoredTextBoxDescription |
|
|
118
|
+
AnchoredImageDescription ;
|
|
102
119
|
|
|
103
120
|
export interface TableFooterType {
|
|
104
121
|
type: 'label'|'formula';
|
|
@@ -363,6 +380,107 @@ export class Workbook {
|
|
|
363
380
|
}
|
|
364
381
|
|
|
365
382
|
}
|
|
383
|
+
else {
|
|
384
|
+
|
|
385
|
+
let style: CellStyle|undefined;
|
|
386
|
+
|
|
387
|
+
const sppr = XMLUtils.FindAll(anchor_node, 'xdr:sp/xdr:spPr')[0];
|
|
388
|
+
if (sppr) {
|
|
389
|
+
style = {};
|
|
390
|
+
const fill = sppr['a:solidFill'];
|
|
391
|
+
if (fill) {
|
|
392
|
+
if (fill['a:schemeClr']?.a$?.val) {
|
|
393
|
+
let m = (fill['a:schemeClr'].a$.val).match(/accent(\d+)/);
|
|
394
|
+
if (m) {
|
|
395
|
+
style.fill = { theme: Number(m[1]) + 3 }
|
|
396
|
+
if (fill['a:schemeClr']['a:lumOff']?.a$?.val) {
|
|
397
|
+
const num = Number(fill['a:schemeClr']['a:lumOff'].a$.val);
|
|
398
|
+
if (!isNaN(num)) {
|
|
399
|
+
style.fill.tint = num / 1e5;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
const tx = XMLUtils.FindAll(anchor_node, 'xdr:sp/xdr:txBody')[0];
|
|
409
|
+
if (tx) {
|
|
410
|
+
|
|
411
|
+
const paragraphs: {
|
|
412
|
+
style?: CellStyle,
|
|
413
|
+
content: {
|
|
414
|
+
text: string,
|
|
415
|
+
style?: CellStyle
|
|
416
|
+
}[],
|
|
417
|
+
}[] = [];
|
|
418
|
+
|
|
419
|
+
/*
|
|
420
|
+
const content: {
|
|
421
|
+
text: string,
|
|
422
|
+
style?: CellStyle,
|
|
423
|
+
}[][] = [];
|
|
424
|
+
*/
|
|
425
|
+
|
|
426
|
+
const p_list = XMLUtils.FindAll(tx, 'a:p');
|
|
427
|
+
for (const paragraph of p_list) {
|
|
428
|
+
const para: { text: string, style?: CellStyle }[] = [];
|
|
429
|
+
let style: CellStyle|undefined;
|
|
430
|
+
|
|
431
|
+
let appr = paragraph['a:pPr'];
|
|
432
|
+
if (appr) {
|
|
433
|
+
style = {};
|
|
434
|
+
if (appr.a$?.algn === 'r') {
|
|
435
|
+
style.horizontal_align = 'right';
|
|
436
|
+
}
|
|
437
|
+
else if (appr.a$?.algn === 'ctr') {
|
|
438
|
+
style.horizontal_align = 'center';
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
let ar = paragraph['a:r'];
|
|
443
|
+
if (ar) {
|
|
444
|
+
if (!Array.isArray(ar)) {
|
|
445
|
+
ar = [ar];
|
|
446
|
+
}
|
|
447
|
+
for (const line of ar) {
|
|
448
|
+
|
|
449
|
+
const entry: { text: string, style?: CellStyle } = {
|
|
450
|
+
text: line['a:t'] || '',
|
|
451
|
+
};
|
|
452
|
+
|
|
453
|
+
// format
|
|
454
|
+
const fmt = line['a:rPr'];
|
|
455
|
+
if (fmt) {
|
|
456
|
+
entry.style = {};
|
|
457
|
+
if (fmt.a$?.b === '1') {
|
|
458
|
+
entry.style.bold = true;
|
|
459
|
+
}
|
|
460
|
+
if (fmt.a$?.i === '1') {
|
|
461
|
+
entry.style.italic = true;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
para.push(entry);
|
|
466
|
+
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
paragraphs.push({ content: para, style });
|
|
471
|
+
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
results.push({
|
|
475
|
+
type: 'textbox',
|
|
476
|
+
style,
|
|
477
|
+
paragraphs,
|
|
478
|
+
anchor,
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
}
|
|
366
484
|
|
|
367
485
|
|
|
368
486
|
}
|