@trebco/treb 29.3.3 → 29.4.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 +11 -11
- package/dist/treb-spreadsheet.mjs +11 -11
- package/dist/treb.d.ts +3 -25
- package/package.json +1 -1
- package/treb-base-types/src/area.ts +25 -1
- package/treb-base-types/src/cell.ts +2 -46
- package/treb-base-types/src/cells.ts +14 -8
- package/treb-base-types/src/import.ts +2 -2
- package/treb-calculator/src/calculator.ts +22 -12
- package/treb-calculator/src/dag/graph.ts +12 -3
- package/treb-calculator/src/expression-calculator.ts +66 -74
- package/treb-calculator/src/functions/base-functions.ts +2 -2
- package/treb-calculator/src/functions/statistics-functions.ts +31 -1
- package/treb-data-model/src/data-validation.ts +44 -0
- package/treb-data-model/src/data_model.ts +12 -8
- package/treb-data-model/src/index.ts +1 -1
- package/treb-data-model/src/named.ts +35 -10
- package/treb-data-model/src/sheet.ts +61 -0
- package/treb-data-model/src/sheet_types.ts +4 -0
- package/treb-embed/src/embedded-spreadsheet.ts +21 -15
- package/treb-embed/src/progress-dialog.ts +4 -1
- package/treb-export/src/export2.ts +27 -14
- package/treb-export/src/import2.ts +58 -12
- package/treb-grid/src/layout/base_layout.ts +2 -11
- package/treb-grid/src/types/grid.ts +29 -18
- package/treb-grid/src/types/grid_base.ts +83 -16
- package/treb-grid/src/types/grid_command.ts +2 -1
- package/treb-parser/src/parser.ts +22 -4
|
@@ -37,11 +37,12 @@
|
|
|
37
37
|
|
|
38
38
|
import { EventSource } from 'treb-utils';
|
|
39
39
|
import type { DataModel, ConditionalFormat, // MacroFunction, SerializedModel, SerializedNamedExpression,
|
|
40
|
-
ViewModel
|
|
40
|
+
ViewModel,
|
|
41
|
+
DataValidation} from 'treb-data-model';
|
|
41
42
|
|
|
42
43
|
import type { Parser, UnitAddress} from 'treb-parser';
|
|
43
44
|
import { type ExpressionUnit, IllegalSheetNameRegex, ParseCSV, DecimalMarkType } from 'treb-parser';
|
|
44
|
-
import { Area, IsCellAddress,
|
|
45
|
+
import { Area, IsCellAddress, ValueType, DefaultTableSortOptions } from 'treb-base-types';
|
|
45
46
|
import type { ICellAddress, IArea, Cell, CellValue, CellStyle, Table, TableSortOptions, TableTheme, Complex, PatchOptions as PatchAreaOptions } from 'treb-base-types';
|
|
46
47
|
|
|
47
48
|
import { Sheet, type SerializeOptions, type Annotation } from 'treb-data-model';
|
|
@@ -922,34 +923,54 @@ export class GridBase {
|
|
|
922
923
|
|
|
923
924
|
protected SetValidationInternal(command: DataValidationCommand): void {
|
|
924
925
|
|
|
925
|
-
let cell: Cell|undefined;
|
|
926
|
-
|
|
927
926
|
const sheet = this.FindSheet(command.area);
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
cell = sheet.cells.GetCell(command.area, true);
|
|
927
|
+
if (!sheet) {
|
|
928
|
+
throw new Error('invalid sheet in set validation');
|
|
931
929
|
}
|
|
932
930
|
|
|
933
|
-
|
|
934
|
-
throw new Error('invalid cell in set validation');
|
|
935
|
-
}
|
|
931
|
+
const target = {start: command.area.start, end: command.area.end };
|
|
936
932
|
|
|
937
933
|
if (command.range) {
|
|
934
|
+
|
|
935
|
+
sheet.AddValidation({
|
|
936
|
+
type: 'range',
|
|
937
|
+
error: !!command.error,
|
|
938
|
+
area: command.range,
|
|
939
|
+
target: [target],
|
|
940
|
+
});
|
|
941
|
+
|
|
942
|
+
/*
|
|
938
943
|
cell.validation = {
|
|
939
944
|
type: ValidationType.Range,
|
|
940
945
|
area: command.range,
|
|
941
946
|
error: !!command.error,
|
|
942
947
|
};
|
|
948
|
+
*/
|
|
949
|
+
|
|
943
950
|
}
|
|
944
951
|
else if (command.list) {
|
|
952
|
+
|
|
953
|
+
sheet.AddValidation({
|
|
954
|
+
type: 'list',
|
|
955
|
+
error: !!command.error,
|
|
956
|
+
list: JSON.parse(JSON.stringify(command.list)),
|
|
957
|
+
target: [target],
|
|
958
|
+
});
|
|
959
|
+
|
|
960
|
+
/*
|
|
945
961
|
cell.validation = {
|
|
946
962
|
type: ValidationType.List,
|
|
947
963
|
list: JSON.parse(JSON.stringify(command.list)),
|
|
948
964
|
error: !!command.error,
|
|
949
965
|
}
|
|
966
|
+
*/
|
|
967
|
+
|
|
950
968
|
}
|
|
951
969
|
else {
|
|
952
|
-
cell.validation = undefined;
|
|
970
|
+
// cell.validation = undefined;
|
|
971
|
+
|
|
972
|
+
sheet.RemoveValidations(target);
|
|
973
|
+
|
|
953
974
|
}
|
|
954
975
|
|
|
955
976
|
}
|
|
@@ -2794,8 +2815,54 @@ export class GridBase {
|
|
|
2794
2815
|
/**
|
|
2795
2816
|
* patch sheet conditionals for insert/delete row/column operations.
|
|
2796
2817
|
* some of them may be deleted.
|
|
2818
|
+
*
|
|
2819
|
+
* UPDATE: using this routine to also patch data validations
|
|
2797
2820
|
*/
|
|
2798
|
-
protected
|
|
2821
|
+
protected PatchConditionalsAndValidations(options: PatchOptions) {
|
|
2822
|
+
|
|
2823
|
+
if (options.sheet.data_validation.length) {
|
|
2824
|
+
|
|
2825
|
+
const delete_list: Set<DataValidation> = new Set();
|
|
2826
|
+
for (const validation of options.sheet.data_validation) {
|
|
2827
|
+
|
|
2828
|
+
const targets: IArea[] = [];
|
|
2829
|
+
for (const area of validation.target) {
|
|
2830
|
+
const updated = Area.PatchArea(area, options);
|
|
2831
|
+
if (updated) {
|
|
2832
|
+
targets.push(updated);
|
|
2833
|
+
}
|
|
2834
|
+
}
|
|
2835
|
+
|
|
2836
|
+
if (targets.length > 0) {
|
|
2837
|
+
|
|
2838
|
+
validation.target = targets;
|
|
2839
|
+
|
|
2840
|
+
// format the range, if necessary
|
|
2841
|
+
|
|
2842
|
+
if (validation.type === 'range') {
|
|
2843
|
+
if (validation.area.start.sheet_id === options.sheet.id) {
|
|
2844
|
+
const updated = Area.PatchArea(validation.area, options);
|
|
2845
|
+
if (updated) {
|
|
2846
|
+
validation.area = updated;
|
|
2847
|
+
}
|
|
2848
|
+
else {
|
|
2849
|
+
delete_list.add(validation);
|
|
2850
|
+
}
|
|
2851
|
+
}
|
|
2852
|
+
}
|
|
2853
|
+
|
|
2854
|
+
}
|
|
2855
|
+
else {
|
|
2856
|
+
delete_list.add(validation);
|
|
2857
|
+
}
|
|
2858
|
+
|
|
2859
|
+
}
|
|
2860
|
+
|
|
2861
|
+
if (delete_list.size) {
|
|
2862
|
+
options.sheet.data_validation = options.sheet.data_validation.filter(test => !delete_list.has(test));
|
|
2863
|
+
}
|
|
2864
|
+
|
|
2865
|
+
}
|
|
2799
2866
|
|
|
2800
2867
|
if (options.sheet.conditional_formats?.length) {
|
|
2801
2868
|
|
|
@@ -2869,7 +2936,7 @@ export class GridBase {
|
|
|
2869
2936
|
}
|
|
2870
2937
|
|
|
2871
2938
|
// conditionals
|
|
2872
|
-
this.
|
|
2939
|
+
this.PatchConditionalsAndValidations({
|
|
2873
2940
|
sheet: target_sheet,
|
|
2874
2941
|
before_column: 0,
|
|
2875
2942
|
column_count: 0,
|
|
@@ -3217,7 +3284,7 @@ export class GridBase {
|
|
|
3217
3284
|
}
|
|
3218
3285
|
|
|
3219
3286
|
// conditionals
|
|
3220
|
-
this.
|
|
3287
|
+
this.PatchConditionalsAndValidations({
|
|
3221
3288
|
sheet: target_sheet,
|
|
3222
3289
|
before_column: command.before_column,
|
|
3223
3290
|
column_count: command.count,
|
|
@@ -4029,8 +4096,8 @@ export class GridBase {
|
|
|
4029
4096
|
// COEDITING: ok
|
|
4030
4097
|
|
|
4031
4098
|
this.SetValidationInternal(command);
|
|
4032
|
-
if (!command.area.sheet_id || command.area.sheet_id === this.active_sheet.id) {
|
|
4033
|
-
flags.render_area = Area.Join(new Area(command.area), flags.render_area);
|
|
4099
|
+
if (!command.area.start.sheet_id || command.area.start.sheet_id === this.active_sheet.id) {
|
|
4100
|
+
flags.render_area = Area.Join(new Area(command.area.start, command.area.end), flags.render_area);
|
|
4034
4101
|
}
|
|
4035
4102
|
break;
|
|
4036
4103
|
|
|
@@ -409,7 +409,7 @@ export class Parser {
|
|
|
409
409
|
for (let i = 0; i < n; i++) {
|
|
410
410
|
transposed[i] = [];
|
|
411
411
|
for (let j = 0; j < m; j++) {
|
|
412
|
-
transposed[i][j] = arr[j][i];
|
|
412
|
+
transposed[i][j] = arr[j] ? arr[j][i] : undefined;
|
|
413
413
|
}
|
|
414
414
|
}
|
|
415
415
|
|
|
@@ -2415,8 +2415,11 @@ export class Parser {
|
|
|
2415
2415
|
if (!c) return null;
|
|
2416
2416
|
position = c.position;
|
|
2417
2417
|
|
|
2418
|
+
// things that look like an address but have row 0 are legal
|
|
2419
|
+
// as names. so this should be a token if r === 0.
|
|
2420
|
+
|
|
2418
2421
|
const r = this.ConsumeAddressRow(position);
|
|
2419
|
-
if (!r) return null;
|
|
2422
|
+
if (!r) return null;
|
|
2420
2423
|
position = r.position;
|
|
2421
2424
|
|
|
2422
2425
|
const label = sheet ?
|
|
@@ -2460,7 +2463,11 @@ export class Parser {
|
|
|
2460
2463
|
|
|
2461
2464
|
/**
|
|
2462
2465
|
* consumes a row, possibly absolute ($). returns the numeric row
|
|
2463
|
-
* (0-based) and metadata
|
|
2466
|
+
* (0-based) and metadata.
|
|
2467
|
+
*
|
|
2468
|
+
* note that something like "X0" is a legal token, because 0 is not
|
|
2469
|
+
* a valid row. but at the same time it can't have a $ in it. although
|
|
2470
|
+
* maybe "X$0" is a token but not a valid name? dunno
|
|
2464
2471
|
*/
|
|
2465
2472
|
protected ConsumeAddressRow(position: number):
|
|
2466
2473
|
{
|
|
@@ -2484,7 +2491,18 @@ export class Parser {
|
|
|
2484
2491
|
else break;
|
|
2485
2492
|
}
|
|
2486
2493
|
|
|
2487
|
-
if (start === position)
|
|
2494
|
+
if (start === position) {
|
|
2495
|
+
return false;
|
|
2496
|
+
}
|
|
2497
|
+
|
|
2498
|
+
// handle token X0. should ~maybe~ handle this only if !absolute
|
|
2499
|
+
// temp leaving this separate from the above test just so it's clear
|
|
2500
|
+
// what we are doing
|
|
2501
|
+
|
|
2502
|
+
if (value === 0) {
|
|
2503
|
+
return false;
|
|
2504
|
+
}
|
|
2505
|
+
|
|
2488
2506
|
return { absolute, row: value - 1, position };
|
|
2489
2507
|
}
|
|
2490
2508
|
|