@trebco/treb 28.10.5 → 28.13.2
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 +12 -12
- package/dist/treb-spreadsheet.mjs +15 -15
- package/dist/treb.d.ts +9 -1
- package/package.json +1 -1
- package/treb-calculator/src/calculator.ts +235 -68
- package/treb-calculator/src/descriptors.ts +5 -0
- package/treb-calculator/src/functions/base-functions.ts +119 -7
- package/treb-calculator/src/functions/text-functions.ts +45 -55
- package/treb-calculator/src/primitives.ts +11 -0
- package/treb-calculator/src/utilities.ts +55 -0
- package/treb-charts/src/chart-utils.ts +24 -3
- package/treb-charts/src/default-chart-renderer.ts +10 -1
- package/treb-charts/src/renderer.ts +34 -3
- package/treb-charts/style/charts.scss +5 -0
- package/treb-embed/src/embedded-spreadsheet.ts +161 -27
- package/treb-embed/style/dark-theme.scss +1 -0
- package/treb-export/src/drawing2/bubble-chart-template.ts +553 -0
- package/treb-export/src/drawing2/chart2.ts +84 -1
- package/treb-export/src/export-worker/export-worker.ts +1 -0
- package/treb-export/src/export2.ts +49 -10
- package/treb-export/src/import2.ts +30 -3
- package/treb-export/src/workbook-style2.ts +78 -14
- package/treb-export/src/workbook2.ts +27 -4
- package/treb-grid/src/editors/editor.ts +7 -0
- package/treb-grid/src/types/grid.ts +20 -9
- package/treb-grid/src/types/grid_base.ts +10 -105
- package/treb-grid/src/types/serialize_options.ts +5 -0
- package/treb-parser/src/parser-types.ts +27 -4
- package/treb-parser/src/parser.ts +74 -36
|
@@ -309,6 +309,17 @@ export const Equals = (a: UnionValue, b: UnionValue): UnionValue => {
|
|
|
309
309
|
|
|
310
310
|
}
|
|
311
311
|
|
|
312
|
+
// this is standard (icase) string equality. we might also need
|
|
313
|
+
// to handle wildcard string matching, although it's not the
|
|
314
|
+
// default case for = operators.
|
|
315
|
+
|
|
316
|
+
if (a.type === ValueType.string && b.type === ValueType.string) {
|
|
317
|
+
return {
|
|
318
|
+
type: ValueType.boolean,
|
|
319
|
+
value: a.value.toLowerCase() === b.value.toLowerCase(),
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
|
|
312
323
|
return { type: ValueType.boolean, value: a.value == b.value }; // note ==
|
|
313
324
|
};
|
|
314
325
|
|
|
@@ -302,3 +302,58 @@ export const ApplyAsArray2 = (base: (a: any, b: any, ...rest: any[]) => UnionVal
|
|
|
302
302
|
}
|
|
303
303
|
};
|
|
304
304
|
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* parse a string with wildcards into a regex pattern
|
|
308
|
+
*
|
|
309
|
+
* from
|
|
310
|
+
* https://exceljet.net/glossary/wildcard
|
|
311
|
+
*
|
|
312
|
+
* Excel has 3 wildcards you can use in your formulas:
|
|
313
|
+
*
|
|
314
|
+
* Asterisk (*) - zero or more characters
|
|
315
|
+
* Question mark (?) - any one character
|
|
316
|
+
* Tilde (~) - escape for literal character (~*) a literal question mark (~?), or a literal tilde (~~)
|
|
317
|
+
*
|
|
318
|
+
* they're pretty liberal with escaping, nothing is an error, just roll with it
|
|
319
|
+
*
|
|
320
|
+
*/
|
|
321
|
+
export const ParseWildcards = (text: string): string => {
|
|
322
|
+
|
|
323
|
+
const result: string[] = [];
|
|
324
|
+
const length = text.length;
|
|
325
|
+
|
|
326
|
+
const escaped_chars = '[\\^$.|?*+()';
|
|
327
|
+
|
|
328
|
+
for (let i = 0; i < length; i++) {
|
|
329
|
+
let char = text[i];
|
|
330
|
+
switch (char) {
|
|
331
|
+
|
|
332
|
+
case '*':
|
|
333
|
+
result.push('.', '*');
|
|
334
|
+
break;
|
|
335
|
+
|
|
336
|
+
case '?':
|
|
337
|
+
result.push('.');
|
|
338
|
+
break;
|
|
339
|
+
|
|
340
|
+
case '~':
|
|
341
|
+
char = text[++i] || '';
|
|
342
|
+
|
|
343
|
+
// eslint-disable-next-line no-fallthrough
|
|
344
|
+
default:
|
|
345
|
+
for (let j = 0; j < escaped_chars.length; j++) {
|
|
346
|
+
if (char === escaped_chars[j]) {
|
|
347
|
+
result.push('\\');
|
|
348
|
+
break;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
result.push(char);
|
|
352
|
+
break;
|
|
353
|
+
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
return result.join('');
|
|
358
|
+
|
|
359
|
+
};
|
|
@@ -310,7 +310,7 @@ export const TransformSeriesData = (raw_data?: UnionValue, default_x?: UnionValu
|
|
|
310
310
|
};
|
|
311
311
|
|
|
312
312
|
/** get a unified scale, and formats */
|
|
313
|
-
export const CommonData = (series: SeriesType[], y_floor?: number, y_ceiling?: number) => {
|
|
313
|
+
export const CommonData = (series: SeriesType[], y_floor?: number, y_ceiling?: number, x_floor?: number, x_ceiling?: number) => {
|
|
314
314
|
|
|
315
315
|
let x_format = '';
|
|
316
316
|
let y_format = '';
|
|
@@ -362,7 +362,14 @@ export const CommonData = (series: SeriesType[], y_floor?: number, y_ceiling?: n
|
|
|
362
362
|
}
|
|
363
363
|
}
|
|
364
364
|
}
|
|
365
|
-
|
|
365
|
+
|
|
366
|
+
if (typeof x_floor !== 'undefined') {
|
|
367
|
+
x_min = Math.min(x_min, x_floor);
|
|
368
|
+
}
|
|
369
|
+
if (typeof x_ceiling !== 'undefined') {
|
|
370
|
+
x_min = Math.max(x_min, x_ceiling);
|
|
371
|
+
}
|
|
372
|
+
|
|
366
373
|
if (typeof y_floor !== 'undefined') {
|
|
367
374
|
y_min = Math.min(y_min, y_floor);
|
|
368
375
|
}
|
|
@@ -438,7 +445,21 @@ const ApplyLabels = (series_list: SeriesType[], pattern: string, category_labels
|
|
|
438
445
|
export const CreateBubbleChart = (args: UnionValue[]): ChartData => {
|
|
439
446
|
|
|
440
447
|
const series: SeriesType[] = TransformSeriesData(args[0]);
|
|
441
|
-
|
|
448
|
+
|
|
449
|
+
let y_floor: number|undefined = undefined;
|
|
450
|
+
let x_floor: number|undefined = undefined;
|
|
451
|
+
|
|
452
|
+
for (const entry of series) {
|
|
453
|
+
|
|
454
|
+
if (typeof entry.x.range?.min === 'number' && entry.x.range.min > 0 && entry.x.range.min < 50) {
|
|
455
|
+
x_floor = 0;
|
|
456
|
+
}
|
|
457
|
+
if (typeof entry.y.range?.min === 'number' && entry.y.range.min > 0 && entry.y.range.min < 50) {
|
|
458
|
+
y_floor = 0;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
const common = CommonData(series, y_floor, undefined, x_floor);
|
|
442
463
|
const title = args[1]?.toString() || undefined;
|
|
443
464
|
const options = args[2]?.toString() || undefined;
|
|
444
465
|
|
|
@@ -196,6 +196,8 @@ export class DefaultChartRenderer implements ChartRendererType {
|
|
|
196
196
|
|
|
197
197
|
// now do type-specific rendering
|
|
198
198
|
|
|
199
|
+
let zeros: number[]|undefined = [];
|
|
200
|
+
|
|
199
201
|
switch (chart_data.type) {
|
|
200
202
|
case 'scatter':
|
|
201
203
|
this.renderer.RenderPoints(area, chart_data.x, chart_data.y, 'mc mc-correlation series-1');
|
|
@@ -203,10 +205,17 @@ export class DefaultChartRenderer implements ChartRendererType {
|
|
|
203
205
|
|
|
204
206
|
case 'bubble':
|
|
205
207
|
|
|
208
|
+
if (chart_data.x_scale.min <= 0 && chart_data.x_scale.max >= 0) {
|
|
209
|
+
zeros[0] = Math.round(Math.abs(chart_data.x_scale.min / chart_data.x_scale.step));
|
|
210
|
+
}
|
|
211
|
+
if (chart_data.y_scale.min <= 0 && chart_data.y_scale.max >= 0) {
|
|
212
|
+
zeros[1] = Math.round(Math.abs(chart_data.y_scale.max / chart_data.y_scale.step));
|
|
213
|
+
}
|
|
214
|
+
|
|
206
215
|
this.renderer.RenderGrid(area,
|
|
207
216
|
chart_data.y_scale.count,
|
|
208
217
|
chart_data.x_scale.count + 1, // (sigh)
|
|
209
|
-
'chart-grid');
|
|
218
|
+
'chart-grid', zeros);
|
|
210
219
|
|
|
211
220
|
for (const [index, series] of chart_data.series.entries()) {
|
|
212
221
|
const series_index = (typeof series.index === 'number') ? series.index : index + 1;
|
|
@@ -968,23 +968,54 @@ export class ChartRenderer {
|
|
|
968
968
|
|
|
969
969
|
}
|
|
970
970
|
|
|
971
|
-
public RenderGrid(area: Area, y_count: number, x_count = 0, classes?: string | string[]): void {
|
|
971
|
+
public RenderGrid(area: Area, y_count: number, x_count = 0, classes?: string | string[], zeros?: number[]): void {
|
|
972
972
|
|
|
973
973
|
const d: string[] = [];
|
|
974
|
+
const d2: string[] = [];
|
|
974
975
|
|
|
975
976
|
let step = area.height / y_count;
|
|
976
977
|
for (let i = 0; i <= y_count; i++) {
|
|
978
|
+
|
|
977
979
|
const y = Math.round(area.top + step * i) - 0.5;
|
|
978
|
-
|
|
980
|
+
|
|
981
|
+
if (zeros && zeros[1] === i) {
|
|
982
|
+
d2.push(`M${area.left} ${y} L${area.right} ${y}`);
|
|
983
|
+
}
|
|
984
|
+
else {
|
|
985
|
+
d.push(`M${area.left} ${y} L${area.right} ${y}`);
|
|
986
|
+
}
|
|
979
987
|
}
|
|
980
988
|
|
|
981
989
|
step = area.width / (x_count - 1);
|
|
982
990
|
for (let i = 0; i < x_count; i++) {
|
|
991
|
+
|
|
983
992
|
const x = Math.round(area.left + step * i) - 0.5;
|
|
984
|
-
|
|
993
|
+
|
|
994
|
+
if (zeros && zeros[0] === i) {
|
|
995
|
+
d2.push(`M${x} ${area.top} L${x} ${area.bottom}`);
|
|
996
|
+
}
|
|
997
|
+
else {
|
|
998
|
+
d.push(`M${x} ${area.top} L${x} ${area.bottom}`);
|
|
999
|
+
}
|
|
985
1000
|
}
|
|
986
1001
|
|
|
987
1002
|
this.group.appendChild(SVGNode('path', {d, class: classes}));
|
|
1003
|
+
if (d2.length) {
|
|
1004
|
+
|
|
1005
|
+
if (classes) {
|
|
1006
|
+
if (!Array.isArray(classes)) {
|
|
1007
|
+
classes = classes + ' zero';
|
|
1008
|
+
}
|
|
1009
|
+
else {
|
|
1010
|
+
classes.push('zero');
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
else {
|
|
1014
|
+
classes = 'zero';
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
this.group.appendChild(SVGNode('path', {d: d2, class: classes}));
|
|
1018
|
+
}
|
|
988
1019
|
|
|
989
1020
|
}
|
|
990
1021
|
|
|
@@ -42,6 +42,8 @@ import type {
|
|
|
42
42
|
CondifionalFormatExpressionOptions,
|
|
43
43
|
ConditionalFormatCellMatchOptions,
|
|
44
44
|
ConditionalFormatCellMatch,
|
|
45
|
+
MacroFunction,
|
|
46
|
+
SerializedNamedExpression,
|
|
45
47
|
} from 'treb-grid';
|
|
46
48
|
|
|
47
49
|
import {
|
|
@@ -413,7 +415,7 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
413
415
|
}
|
|
414
416
|
|
|
415
417
|
/** for destruction */
|
|
416
|
-
protected
|
|
418
|
+
protected view_node?: HTMLElement;
|
|
417
419
|
|
|
418
420
|
/** for destruction */
|
|
419
421
|
protected key_listener?: (event: KeyboardEvent) => void;
|
|
@@ -844,7 +846,7 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
844
846
|
// elements. but we don't add a default; rather we use a template
|
|
845
847
|
|
|
846
848
|
const template = container.querySelector('.treb-view-template') as HTMLTemplateElement;
|
|
847
|
-
this.
|
|
849
|
+
this.view_node = template.content.firstElementChild?.cloneNode(true) as HTMLElement;
|
|
848
850
|
|
|
849
851
|
// this is a little weird but we're inserting at the front. the
|
|
850
852
|
// reason for this is that we only want to use one resize handle,
|
|
@@ -852,13 +854,13 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
852
854
|
|
|
853
855
|
// we could work around this, really we're just being lazy.
|
|
854
856
|
|
|
855
|
-
container.prepend(this.
|
|
857
|
+
container.prepend(this.view_node);
|
|
856
858
|
|
|
857
859
|
|
|
858
860
|
// this.node = container;
|
|
859
861
|
// this.node = this.view;
|
|
860
862
|
|
|
861
|
-
this.
|
|
863
|
+
this.view_node.addEventListener('focusin', () => {
|
|
862
864
|
if (this.focus_target !== this) {
|
|
863
865
|
this.Publish({ type: 'focus-view' });
|
|
864
866
|
this.focus_target = this;
|
|
@@ -878,14 +880,14 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
878
880
|
|
|
879
881
|
// const view = container.querySelector('.treb-view') as HTMLElement;
|
|
880
882
|
|
|
881
|
-
this.grid.Initialize(this.
|
|
883
|
+
this.grid.Initialize(this.view_node, toll_initial_render);
|
|
882
884
|
|
|
883
885
|
// dnd
|
|
884
886
|
|
|
885
887
|
if (this.options.dnd) {
|
|
886
|
-
this.
|
|
887
|
-
this.
|
|
888
|
-
this.
|
|
888
|
+
this.view_node.addEventListener('dragenter', (event) => this.HandleDrag(event));
|
|
889
|
+
this.view_node.addEventListener('dragover', (event) => this.HandleDrag(event));
|
|
890
|
+
this.view_node.addEventListener('drop', (event) => this.HandleDrop(event));
|
|
889
891
|
}
|
|
890
892
|
|
|
891
893
|
// set up grid events
|
|
@@ -1244,19 +1246,19 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
1244
1246
|
sheet.grid.grid_events.CancelAll();
|
|
1245
1247
|
sheet.events.CancelAll();
|
|
1246
1248
|
|
|
1247
|
-
if (sheet.
|
|
1249
|
+
if (sheet.view_node?.parentElement) {
|
|
1248
1250
|
|
|
1249
1251
|
// remove listener
|
|
1250
1252
|
if (sheet.key_listener) {
|
|
1251
|
-
sheet.
|
|
1253
|
+
sheet.view_node.parentElement.removeEventListener('keydown', sheet.key_listener);
|
|
1252
1254
|
}
|
|
1253
1255
|
|
|
1254
1256
|
// remove node
|
|
1255
|
-
sheet.
|
|
1257
|
+
sheet.view_node.parentElement.removeChild(sheet.view_node);
|
|
1256
1258
|
}
|
|
1257
1259
|
|
|
1258
1260
|
// in case other view was focused
|
|
1259
|
-
this.
|
|
1261
|
+
this.view_node?.focus();
|
|
1260
1262
|
|
|
1261
1263
|
// usually this results in us getting larger, we may need to update
|
|
1262
1264
|
this.Resize();
|
|
@@ -1285,7 +1287,7 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
1285
1287
|
const view = this.CreateView();
|
|
1286
1288
|
view.grid.EnsureActiveSheet(true);
|
|
1287
1289
|
|
|
1288
|
-
view.
|
|
1290
|
+
view.view_node?.addEventListener('focusin', () => {
|
|
1289
1291
|
if (this.focus_target !== view) {
|
|
1290
1292
|
this.Publish({ type: 'focus-view' });
|
|
1291
1293
|
this.focus_target = view;
|
|
@@ -2244,12 +2246,16 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
2244
2246
|
this.parser.flags.r1c1 = r1c1;
|
|
2245
2247
|
|
|
2246
2248
|
if (argument_separator === ',') {
|
|
2247
|
-
this.parser.
|
|
2248
|
-
|
|
2249
|
+
this.parser.SetLocaleSettings(DecimalMarkType.Period);
|
|
2250
|
+
|
|
2251
|
+
// this.parser.argument_separator = ArgumentSeparatorType.Comma;
|
|
2252
|
+
// this.parser.decimal_mark = DecimalMarkType.Period;
|
|
2249
2253
|
}
|
|
2250
2254
|
else {
|
|
2251
|
-
this.parser.
|
|
2252
|
-
|
|
2255
|
+
this.parser.SetLocaleSettings(DecimalMarkType.Comma);
|
|
2256
|
+
|
|
2257
|
+
// this.parser.argument_separator = ArgumentSeparatorType.Semicolon;
|
|
2258
|
+
// this.parser.decimal_mark = DecimalMarkType.Comma;
|
|
2253
2259
|
}
|
|
2254
2260
|
|
|
2255
2261
|
const result = this.parser.Parse(formula);
|
|
@@ -2354,12 +2360,16 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
2354
2360
|
*/
|
|
2355
2361
|
|
|
2356
2362
|
if (argument_separator === ',') {
|
|
2357
|
-
this.parser.
|
|
2358
|
-
|
|
2363
|
+
this.parser.SetLocaleSettings(DecimalMarkType.Period);
|
|
2364
|
+
|
|
2365
|
+
// this.parser.argument_separator = ArgumentSeparatorType.Comma;
|
|
2366
|
+
// this.parser.decimal_mark = DecimalMarkType.Period;
|
|
2359
2367
|
}
|
|
2360
2368
|
else {
|
|
2361
|
-
this.parser.
|
|
2362
|
-
|
|
2369
|
+
this.parser.SetLocaleSettings(DecimalMarkType.Comma);
|
|
2370
|
+
|
|
2371
|
+
// this.parser.argument_separator = ArgumentSeparatorType.Semicolon;
|
|
2372
|
+
// this.parser.decimal_mark = DecimalMarkType.Comma;
|
|
2363
2373
|
}
|
|
2364
2374
|
|
|
2365
2375
|
// const r1c1_state = this.parser.flags.r1c1;
|
|
@@ -2749,13 +2759,14 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
2749
2759
|
|
|
2750
2760
|
// FIXME: type
|
|
2751
2761
|
|
|
2752
|
-
const serialized: SerializedModel = this.grid.Serialize({
|
|
2762
|
+
const serialized: SerializedModel = this.Serialize({ // this.grid.Serialize({
|
|
2753
2763
|
rendered_values: true,
|
|
2754
2764
|
expand_arrays: true,
|
|
2755
2765
|
export_colors: true,
|
|
2756
2766
|
decorated_cells: true,
|
|
2757
2767
|
tables: true,
|
|
2758
2768
|
share_resources: false,
|
|
2769
|
+
export_functions: true,
|
|
2759
2770
|
});
|
|
2760
2771
|
|
|
2761
2772
|
// why do _we_ put this in, instead of the grid method?
|
|
@@ -3523,6 +3534,9 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
3523
3534
|
/**
|
|
3524
3535
|
* Create a macro function.
|
|
3525
3536
|
*
|
|
3537
|
+
* FIXME: this needs a control for argument separator, like other
|
|
3538
|
+
* functions that use formulas (@see SetRange)
|
|
3539
|
+
*
|
|
3526
3540
|
* @public
|
|
3527
3541
|
*/
|
|
3528
3542
|
public DefineFunction(name: string, argument_names: string | string[] = '', function_def = '0'): void {
|
|
@@ -3592,7 +3606,8 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
3592
3606
|
...options,
|
|
3593
3607
|
};
|
|
3594
3608
|
|
|
3595
|
-
const grid_data = this.grid.Serialize(options);
|
|
3609
|
+
// const grid_data = this.grid.Serialize(options);
|
|
3610
|
+
const grid_data = this.Serialize(options);
|
|
3596
3611
|
|
|
3597
3612
|
// NOTE: these are not really env vars. we replace them at build time
|
|
3598
3613
|
// via a webpack plugin. using the env syntax lets them look "real" at
|
|
@@ -4405,6 +4420,121 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
4405
4420
|
|
|
4406
4421
|
// --- internal (protected) methods ------------------------------------------
|
|
4407
4422
|
|
|
4423
|
+
// --- moved from grid/grid base ---------------------------------------------
|
|
4424
|
+
|
|
4425
|
+
|
|
4426
|
+
/**
|
|
4427
|
+
* serialize data model. moved from grid/grid base. this is moved so we
|
|
4428
|
+
* have access to the calculator, which we want so we can do function
|
|
4429
|
+
* translation on some new functions that don't necessarily map 1:1 to
|
|
4430
|
+
* XLSX functions. we can also do cleanup on functions where we're less
|
|
4431
|
+
* strict about arguments (ROUND, for example).
|
|
4432
|
+
*
|
|
4433
|
+
*/
|
|
4434
|
+
protected Serialize(options: SerializeOptions = {}): SerializedModel {
|
|
4435
|
+
|
|
4436
|
+
const active_sheet = this.grid.active_sheet; // I thought this was in view? (...)
|
|
4437
|
+
|
|
4438
|
+
active_sheet.selection = JSON.parse(JSON.stringify(this.grid.GetSelection()));
|
|
4439
|
+
|
|
4440
|
+
// same for scroll offset
|
|
4441
|
+
|
|
4442
|
+
const scroll_offset = this.grid.ScrollOffset();
|
|
4443
|
+
if (scroll_offset) {
|
|
4444
|
+
active_sheet.scroll_offset = scroll_offset; // this.grid.layout.scroll_offset;
|
|
4445
|
+
}
|
|
4446
|
+
|
|
4447
|
+
// NOTE: annotations moved to sheets, they will be serialized in the sheets
|
|
4448
|
+
|
|
4449
|
+
const sheet_data = this.model.sheets.list.map((sheet) => sheet.toJSON(options));
|
|
4450
|
+
|
|
4451
|
+
// OK, not serializing tables in cells anymore. old comment about this:
|
|
4452
|
+
//
|
|
4453
|
+
// at the moment, tables are being serialized in cells. if we put them
|
|
4454
|
+
// in here, then we have two records of the same data. that would be bad.
|
|
4455
|
+
// I think this is probably the correct place, but if we put them here
|
|
4456
|
+
// we need to stop serializing in cells. and I'm not sure that there are
|
|
4457
|
+
// not some side-effects to that. hopefully not, but (...)
|
|
4458
|
+
//
|
|
4459
|
+
|
|
4460
|
+
let tables: Table[] | undefined;
|
|
4461
|
+
if (this.model.tables.size > 0) {
|
|
4462
|
+
tables = Array.from(this.model.tables.values());
|
|
4463
|
+
}
|
|
4464
|
+
|
|
4465
|
+
// NOTE: moving into a structured object (the sheet data is also structured,
|
|
4466
|
+
// of course) but we are moving things out of sheet (just named ranges atm))
|
|
4467
|
+
|
|
4468
|
+
let macro_functions: MacroFunction[] | undefined;
|
|
4469
|
+
|
|
4470
|
+
if (this.model.macro_functions.size) {
|
|
4471
|
+
macro_functions = [];
|
|
4472
|
+
for (const macro of this.model.macro_functions.values()) {
|
|
4473
|
+
macro_functions.push({
|
|
4474
|
+
...macro,
|
|
4475
|
+
expression: undefined,
|
|
4476
|
+
});
|
|
4477
|
+
}
|
|
4478
|
+
}
|
|
4479
|
+
|
|
4480
|
+
// when serializing named expressions, we have to make sure
|
|
4481
|
+
// that there's a sheet name in any address/range.
|
|
4482
|
+
|
|
4483
|
+
const named_expressions: SerializedNamedExpression[] = [];
|
|
4484
|
+
if (this.model.named_expressions) {
|
|
4485
|
+
|
|
4486
|
+
for (const [name, expr] of this.model.named_expressions) {
|
|
4487
|
+
this.parser.Walk(expr, unit => {
|
|
4488
|
+
if (unit.type === 'address' || unit.type === 'range') {
|
|
4489
|
+
const test = unit.type === 'range' ? unit.start : unit;
|
|
4490
|
+
|
|
4491
|
+
test.absolute_column = test.absolute_row = true;
|
|
4492
|
+
|
|
4493
|
+
if (!test.sheet) {
|
|
4494
|
+
if (test.sheet_id) {
|
|
4495
|
+
const sheet = this.model.sheets.Find(test.sheet_id);
|
|
4496
|
+
if (sheet) {
|
|
4497
|
+
test.sheet = sheet.name;
|
|
4498
|
+
}
|
|
4499
|
+
}
|
|
4500
|
+
if (!test.sheet) {
|
|
4501
|
+
test.sheet = active_sheet.name;
|
|
4502
|
+
}
|
|
4503
|
+
}
|
|
4504
|
+
|
|
4505
|
+
if (unit.type === 'range') {
|
|
4506
|
+
unit.end.absolute_column = unit.end.absolute_row = true;
|
|
4507
|
+
}
|
|
4508
|
+
|
|
4509
|
+
return false;
|
|
4510
|
+
}
|
|
4511
|
+
else if (unit.type === 'call' && options.export_functions) {
|
|
4512
|
+
// ...
|
|
4513
|
+
}
|
|
4514
|
+
return true;
|
|
4515
|
+
});
|
|
4516
|
+
const rendered = this.parser.Render(expr, { missing: '' });
|
|
4517
|
+
named_expressions.push({
|
|
4518
|
+
name, expression: rendered
|
|
4519
|
+
});
|
|
4520
|
+
}
|
|
4521
|
+
}
|
|
4522
|
+
|
|
4523
|
+
return {
|
|
4524
|
+
sheet_data,
|
|
4525
|
+
active_sheet: active_sheet.id,
|
|
4526
|
+
named_ranges: this.model.named_ranges.Count() ?
|
|
4527
|
+
this.model.named_ranges.Serialize() :
|
|
4528
|
+
undefined,
|
|
4529
|
+
macro_functions,
|
|
4530
|
+
tables,
|
|
4531
|
+
named_expressions: named_expressions.length ? named_expressions : undefined,
|
|
4532
|
+
};
|
|
4533
|
+
|
|
4534
|
+
}
|
|
4535
|
+
|
|
4536
|
+
// --- /moved ----------------------------------------------------------------
|
|
4537
|
+
|
|
4408
4538
|
/**
|
|
4409
4539
|
*
|
|
4410
4540
|
*/
|
|
@@ -5531,14 +5661,18 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
5531
5661
|
// FIXME: also we should unify on types for decimal, argument separator
|
|
5532
5662
|
|
|
5533
5663
|
if (data.decimal_mark === '.') {
|
|
5534
|
-
parser.decimal_mark = DecimalMarkType.Period;
|
|
5535
|
-
parser.argument_separator = ArgumentSeparatorType.Comma;
|
|
5664
|
+
// parser.decimal_mark = DecimalMarkType.Period;
|
|
5665
|
+
// parser.argument_separator = ArgumentSeparatorType.Comma;
|
|
5666
|
+
parser.SetLocaleSettings(DecimalMarkType.Period);
|
|
5667
|
+
|
|
5536
5668
|
target_decimal_mark = DecimalMarkType.Comma;
|
|
5537
5669
|
target_argument_separator = ArgumentSeparatorType.Semicolon;
|
|
5538
5670
|
}
|
|
5539
5671
|
else {
|
|
5540
|
-
parser.decimal_mark = DecimalMarkType.Comma;
|
|
5541
|
-
parser.argument_separator = ArgumentSeparatorType.Semicolon;
|
|
5672
|
+
// parser.decimal_mark = DecimalMarkType.Comma;
|
|
5673
|
+
// parser.argument_separator = ArgumentSeparatorType.Semicolon;
|
|
5674
|
+
parser.SetLocaleSettings(DecimalMarkType.Comma);
|
|
5675
|
+
|
|
5542
5676
|
target_decimal_mark = DecimalMarkType.Period;
|
|
5543
5677
|
target_argument_separator = ArgumentSeparatorType.Comma;
|
|
5544
5678
|
}
|