@trebco/treb 28.13.2 → 28.15.1
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 +15 -15
- 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 +405 -57
- package/treb-calculator/src/utilities.ts +37 -24
- 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 +66 -13
- package/treb-export/src/shared-strings2.ts +1 -1
- package/treb-export/src/workbook-style2.ts +25 -64
- 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 +48 -3
- package/treb-grid/src/types/annotation.ts +17 -3
- package/treb-grid/src/types/grid.ts +9 -1
- package/treb-grid/src/types/grid_options.ts +3 -2
- package/treb-grid/src/types/named_range.ts +8 -1
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
<div data-bind='message' class='treb-embed-dialog-message'></div>
|
|
39
39
|
<div data-bind='about' class='treb-embed-dialog-body'></div>
|
|
40
40
|
</div>
|
|
41
|
-
<button type='button' title='
|
|
41
|
+
<button type='button' data-title='close_dialog' data-bind='close' class='treb-close-box'>
|
|
42
42
|
<svg viewBox='0 0 16 16'>
|
|
43
43
|
<path d='M11.854 4.146a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708-.708l7-7a.5.5 0 0 1 .708 0z'/>
|
|
44
44
|
<path d='M4.146 4.146a.5.5 0 0 0 0 .708l7 7a.5.5 0 0 0 .708-.708l-7-7a.5.5 0 0 0-.708 0z'/>
|
|
@@ -62,6 +62,9 @@
|
|
|
62
62
|
|
|
63
63
|
<div class="treb-formula-bar notranslate" hidden>
|
|
64
64
|
<div class="treb-address-label"><div></div></div>
|
|
65
|
+
<button class="treb-insert-function-button"
|
|
66
|
+
data-title="insert_function"
|
|
67
|
+
data-conditional="insert-function">𝑓<small>(x)</small></button>
|
|
65
68
|
<div class="treb-editor-container">
|
|
66
69
|
<div contenteditable="true"></div>
|
|
67
70
|
</div>
|
|
@@ -95,7 +98,7 @@
|
|
|
95
98
|
-->
|
|
96
99
|
|
|
97
100
|
<!-- converted to button, more appropriate -->
|
|
98
|
-
<button class="treb-delete-tab" title="
|
|
101
|
+
<button class="treb-delete-tab" data-title="delete_sheet" data-command="delete-tab" data-conditional="delete-tab">
|
|
99
102
|
<svg tabindex="-1" viewbox='0 0 16 16'><path d='M4,4 L12,12 M12,4 L4,12'/></svg>
|
|
100
103
|
</button>
|
|
101
104
|
|
|
@@ -105,7 +108,8 @@
|
|
|
105
108
|
</div>
|
|
106
109
|
|
|
107
110
|
<!-- converted to button, more appropriate -->
|
|
108
|
-
<button class="treb-add-tab" data-command="add-tab" data-conditional="add-tab"
|
|
111
|
+
<button class="treb-add-tab" data-command="add-tab" data-conditional="add-tab"
|
|
112
|
+
data-title="add_sheet">+</button>
|
|
109
113
|
|
|
110
114
|
<!--
|
|
111
115
|
we removed the junk node with "flex grow" to split the layout, in
|
|
@@ -125,7 +129,8 @@
|
|
|
125
129
|
|
|
126
130
|
<div class="treb-revert-indicator"
|
|
127
131
|
data-command="revert-indicator"
|
|
128
|
-
title="
|
|
132
|
+
data-title="document_modified"
|
|
133
|
+
></div>
|
|
129
134
|
|
|
130
135
|
</div> <!-- /treb-view -->
|
|
131
136
|
</template>
|
|
@@ -133,13 +138,13 @@
|
|
|
133
138
|
</div>
|
|
134
139
|
|
|
135
140
|
<div class="treb-layout-sidebar treb-animate">
|
|
136
|
-
<button data-command="recalculate" title="
|
|
137
|
-
<button data-command="toggle-toolbar" data-conditional="toolbar" title="
|
|
138
|
-
<button data-command="export-xlsx" data-conditional="export" title="
|
|
139
|
-
<button data-command="revert" data-conditional="revert" title="
|
|
140
|
-
<button data-command="about" title="
|
|
141
|
+
<button data-command="recalculate" data-title="recalculate"></button>
|
|
142
|
+
<button data-command="toggle-toolbar" data-conditional="toolbar" data-title="toggle_toolbar"></button>
|
|
143
|
+
<button data-command="export-xlsx" data-conditional="export" data-title="export"></button>
|
|
144
|
+
<button data-command="revert" data-conditional="revert" data-title="revert"></button>
|
|
145
|
+
<button data-command="about" data-title="about"></button>
|
|
141
146
|
</div>
|
|
142
147
|
|
|
143
|
-
<button class="treb-toggle-sidebar-button" title="
|
|
148
|
+
<button class="treb-toggle-sidebar-button" data-title="toggle_sidebar"></button>
|
|
144
149
|
|
|
145
150
|
</div>
|
|
@@ -49,12 +49,12 @@
|
|
|
49
49
|
|
|
50
50
|
<div class="group">
|
|
51
51
|
<button data-command="wrap-text" title="Wrap text"></button>
|
|
52
|
-
<button data-command="merge-cells" data-id="merge" data-title="Merge cells" data-active-title="Unmerge cells"></button>
|
|
53
|
-
<button data-command="lock-cells" data-title="Lock cells" data-active-title="Unlock cells"></button>
|
|
54
|
-
<button data-command="freeze-panes" data-title="Freeze panes" data-active-title="Unfreeze panes" freeze-button></button>
|
|
55
|
-
<button data-command="insert-table" data-icon="table" data-title="Insert table" data-active-title="Remove table" table-button></button>
|
|
52
|
+
<button data-command="merge-cells" data-id="merge" data-inactive-title="Merge cells" data-active-title="Unmerge cells"></button>
|
|
53
|
+
<button data-command="lock-cells" data-inactive-title="Lock cells" data-active-title="Unlock cells"></button>
|
|
54
|
+
<button data-command="freeze-panes" data-inactive-title="Freeze panes" data-active-title="Unfreeze panes" freeze-button></button>
|
|
55
|
+
<button data-command="insert-table" data-icon="table" data-inactive-title="Insert table" data-active-title="Remove table" table-button></button>
|
|
56
56
|
<div class="treb-menu">
|
|
57
|
-
<button data-icon="comment" data-title="Comment" data-active-title="Update comment"></button>
|
|
57
|
+
<button data-icon="comment" data-inactive-title="Comment" data-active-title="Update comment"></button>
|
|
58
58
|
<div class="treb-comment-box">
|
|
59
59
|
<textarea></textarea>
|
|
60
60
|
<div>
|
|
@@ -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';
|
|
@@ -93,7 +93,7 @@ export class Importer {
|
|
|
93
93
|
ref?: string;
|
|
94
94
|
},
|
|
95
95
|
};
|
|
96
|
-
},
|
|
96
|
+
},
|
|
97
97
|
shared_formulae: SharedFormulaMap,
|
|
98
98
|
arrays: RangeType[],
|
|
99
99
|
merges: RangeType[],
|
|
@@ -117,11 +117,9 @@ export class Importer {
|
|
|
117
117
|
// console.info(element);
|
|
118
118
|
|
|
119
119
|
let value: undefined | number | boolean | string;
|
|
120
|
-
// let type: ValueType = ValueType.undefined;
|
|
121
120
|
let type: SerializedValueType = 'undefined';
|
|
122
121
|
|
|
123
122
|
let calculated_value: undefined | number | boolean | string;
|
|
124
|
-
// let calculated_type: ValueType = ValueType.undefined;
|
|
125
123
|
let calculated_type: SerializedValueType = 'undefined';
|
|
126
124
|
|
|
127
125
|
// QUESTIONS:
|
|
@@ -170,8 +168,13 @@ export class Importer {
|
|
|
170
168
|
const parse_result = this.parser.Parse(formula); // l10n?
|
|
171
169
|
if (parse_result.expression) {
|
|
172
170
|
this.parser.Walk(parse_result.expression, (unit) => {
|
|
173
|
-
if (unit.type === 'call'
|
|
174
|
-
|
|
171
|
+
if (unit.type === 'call') {
|
|
172
|
+
if (/^_xll\./.test(unit.name)) {
|
|
173
|
+
unit.name = unit.name.substring(5);
|
|
174
|
+
}
|
|
175
|
+
else if (/^_xlfn\./.test(unit.name)) {
|
|
176
|
+
unit.name = unit.name.substring(6);
|
|
177
|
+
}
|
|
175
178
|
}
|
|
176
179
|
return true;
|
|
177
180
|
});
|
|
@@ -390,6 +393,23 @@ export class Importer {
|
|
|
390
393
|
|
|
391
394
|
case 'expression':
|
|
392
395
|
if (rule.formula) {
|
|
396
|
+
|
|
397
|
+
if (typeof rule.formula !== 'string') {
|
|
398
|
+
if (rule.formula.t$) {
|
|
399
|
+
|
|
400
|
+
// the only case (to date) we've seen here is that the attribute
|
|
401
|
+
// is "xml:space=preserve", which we can ignore (are you sure?)
|
|
402
|
+
// (should we check that?)
|
|
403
|
+
|
|
404
|
+
rule.formula = rule.formula.t$;
|
|
405
|
+
|
|
406
|
+
}
|
|
407
|
+
else {
|
|
408
|
+
console.info("unexpected conditional expression", {rule});
|
|
409
|
+
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
393
413
|
let style = {};
|
|
394
414
|
|
|
395
415
|
if (rule.a$.dxfId) {
|
|
@@ -498,16 +518,25 @@ export class Importer {
|
|
|
498
518
|
const conditional_formatting = FindAll('worksheet/conditionalFormatting');
|
|
499
519
|
for (const element of conditional_formatting) {
|
|
500
520
|
if (element.a$?.sqref ){
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
521
|
+
|
|
522
|
+
// FIXME: this attribute might include multiple ranges? e.g.:
|
|
523
|
+
//
|
|
524
|
+
// <conditionalFormatting sqref="B31:I31 B10:E30 G10:I30 F14:F15">
|
|
525
|
+
|
|
526
|
+
const parts = element.a$.sqref.split(/\s+/);
|
|
527
|
+
for (const part of parts) {
|
|
528
|
+
const area = sheet.TranslateAddress(part);
|
|
529
|
+
if (element.cfRule) {
|
|
530
|
+
const rules = Array.isArray(element.cfRule) ? element.cfRule : [element.cfRule];
|
|
531
|
+
for (const rule of rules) {
|
|
532
|
+
const format = this.ParseConditionalFormat(area, rule);
|
|
533
|
+
if (format) {
|
|
534
|
+
conditional_formats.push(format);
|
|
535
|
+
}
|
|
508
536
|
}
|
|
509
537
|
}
|
|
510
538
|
}
|
|
539
|
+
|
|
511
540
|
}
|
|
512
541
|
}
|
|
513
542
|
|
|
@@ -808,6 +837,7 @@ export class Importer {
|
|
|
808
837
|
const drawings = FindAll('worksheet/drawing');
|
|
809
838
|
const chart_descriptors: AnchoredChartDescription[] = [];
|
|
810
839
|
const image_descriptors: AnchoredImageDescription[] = [];
|
|
840
|
+
const textbox_descriptors: AnchoredTextBoxDescription[] = [];
|
|
811
841
|
|
|
812
842
|
for (const child of drawings) {
|
|
813
843
|
|
|
@@ -832,6 +862,9 @@ export class Importer {
|
|
|
832
862
|
case 'image':
|
|
833
863
|
image_descriptors.push(entry);
|
|
834
864
|
break;
|
|
865
|
+
case 'textbox':
|
|
866
|
+
textbox_descriptors.push(entry);
|
|
867
|
+
break;
|
|
835
868
|
}
|
|
836
869
|
}
|
|
837
870
|
}
|
|
@@ -873,6 +906,26 @@ export class Importer {
|
|
|
873
906
|
|
|
874
907
|
};
|
|
875
908
|
|
|
909
|
+
for (const descriptor of textbox_descriptors) {
|
|
910
|
+
|
|
911
|
+
const layout: AnnotationLayout = {
|
|
912
|
+
tl: AnchorToCorner(descriptor.anchor.from),
|
|
913
|
+
br: AnchorToCorner(descriptor.anchor.to),
|
|
914
|
+
};
|
|
915
|
+
|
|
916
|
+
// console.info({descriptor});
|
|
917
|
+
|
|
918
|
+
annotations.push({
|
|
919
|
+
layout,
|
|
920
|
+
type: 'textbox',
|
|
921
|
+
data: {
|
|
922
|
+
style: descriptor.style,
|
|
923
|
+
paragraphs: descriptor.paragraphs,
|
|
924
|
+
}
|
|
925
|
+
});
|
|
926
|
+
|
|
927
|
+
}
|
|
928
|
+
|
|
876
929
|
for (const descriptor of image_descriptors) {
|
|
877
930
|
if (descriptor && descriptor.image) {
|
|
878
931
|
|
|
@@ -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
|