@trebco/treb 28.17.4 → 29.1.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 +12 -12
- package/dist/treb.d.ts +121 -82
- package/eslint.config.js +21 -0
- package/package.json +6 -6
- package/treb-base-types/src/area.ts +4 -2
- package/treb-base-types/src/cell.ts +1 -1
- package/treb-base-types/src/cells.ts +16 -7
- package/treb-base-types/src/dom-utilities.ts +4 -2
- package/treb-base-types/src/import.ts +2 -2
- package/treb-base-types/src/rectangle.ts +5 -5
- package/treb-base-types/src/union.ts +6 -1
- package/treb-base-types/src/value-type.ts +1 -1
- package/treb-calculator/src/calculator.ts +114 -165
- package/treb-calculator/src/dag/calculation_leaf_vertex.ts +1 -2
- package/treb-calculator/src/dag/graph.ts +3 -3
- package/treb-calculator/src/dag/spreadsheet_vertex.ts +2 -2
- package/treb-calculator/src/dag/state_leaf_vertex.ts +2 -4
- package/treb-calculator/src/descriptors.ts +28 -2
- package/treb-calculator/src/expression-calculator.ts +25 -34
- package/treb-calculator/src/function-error.ts +2 -2
- package/treb-calculator/src/function-library.ts +16 -0
- package/treb-calculator/src/functions/base-functions.ts +185 -211
- package/treb-calculator/src/functions/checkbox.ts +0 -1
- package/treb-calculator/src/functions/complex-functions.ts +49 -47
- package/treb-calculator/src/functions/finance-functions.ts +10 -10
- package/treb-calculator/src/functions/function-utilities.ts +26 -0
- package/treb-calculator/src/functions/information-functions.ts +21 -41
- package/treb-calculator/src/functions/matrix-functions.ts +8 -1
- package/treb-calculator/src/functions/sparkline.ts +6 -4
- package/treb-calculator/src/functions/statistics-functions.ts +21 -17
- package/treb-calculator/src/functions/text-functions.ts +14 -13
- package/treb-calculator/src/primitives.ts +48 -37
- package/treb-calculator/src/utilities.ts +117 -134
- package/treb-charts/src/chart-functions.ts +3 -3
- package/treb-charts/src/chart-types.ts +42 -1
- package/treb-charts/src/chart-utils.ts +155 -113
- package/treb-charts/src/chart.ts +6 -5
- package/treb-charts/src/default-chart-renderer.ts +6 -5
- package/treb-charts/src/renderer.ts +12 -11
- package/treb-charts/src/util.ts +25 -36
- package/treb-data-model/package.json +5 -0
- package/{treb-grid/src/types → treb-data-model/src}/annotation.ts +2 -2
- package/{treb-grid/src/types → treb-data-model/src}/conditional_format.ts +20 -0
- package/{treb-grid/src/types → treb-data-model/src}/data_model.ts +231 -133
- package/treb-data-model/src/index.ts +45 -0
- package/{treb-grid/src/types/named_range.ts → treb-data-model/src/named.ts} +459 -376
- package/{treb-grid/src/types → treb-data-model/src}/sheet.ts +13 -5
- package/treb-data-model/src/sheet_collection.ts +114 -0
- package/{treb-grid/src/types → treb-data-model/src}/sheet_types.ts +6 -3
- package/treb-embed/modern.tsconfig.json +1 -0
- package/treb-embed/src/custom-element/spreadsheet-constructor.ts +2 -3
- package/treb-embed/src/embedded-spreadsheet.ts +125 -270
- package/treb-embed/src/selection-state.ts +1 -1
- package/treb-embed/src/toolbar-message.ts +1 -1
- package/treb-embed/src/types.ts +13 -5
- package/treb-export/src/export-worker/export-worker.ts +22 -7
- package/treb-export/src/export2.ts +110 -41
- package/treb-export/src/import2.ts +6 -5
- package/treb-export/src/workbook2.ts +31 -13
- package/treb-export/src/xml-utils.ts +5 -1
- package/treb-format/src/format.ts +8 -6
- package/treb-grid/src/editors/autocomplete.ts +2 -2
- package/treb-grid/src/editors/autocomplete_matcher.ts +57 -19
- package/treb-grid/src/editors/editor.ts +27 -25
- package/treb-grid/src/editors/formula_bar.ts +5 -5
- package/treb-grid/src/editors/overlay_editor.ts +1 -2
- package/treb-grid/src/index.ts +0 -11
- package/treb-grid/src/layout/base_layout.ts +20 -8
- package/treb-grid/src/layout/grid_layout.ts +2 -2
- package/treb-grid/src/layout/mock-layout.ts +5 -6
- package/treb-grid/src/render/selection-renderer.ts +2 -3
- package/treb-grid/src/render/tile_renderer.ts +1 -1
- package/treb-grid/src/types/grid.ts +95 -66
- package/treb-grid/src/types/grid_base.ts +76 -60
- package/treb-grid/src/types/grid_command.ts +3 -2
- package/treb-grid/src/types/grid_events.ts +12 -6
- package/treb-grid/src/types/tab_bar.ts +1 -2
- package/treb-parser/src/parser-types.ts +2 -1
- package/treb-parser/src/parser.ts +7 -5
- package/treb-utils/src/event_source.ts +1 -1
- package/treb-utils/src/serialize_html.ts +31 -6
- package/.eslintignore +0 -8
- package/.eslintrc.cjs +0 -168
- package/treb-grid/src/layout/rectangle_cache.ts +0 -86
- /package/{treb-grid/src/types → treb-data-model/src}/serialize_options.ts +0 -0
- /package/{treb-grid/src/types/grid_selection.ts → treb-data-model/src/sheet_selection.ts} +0 -0
|
@@ -48,9 +48,7 @@ import {
|
|
|
48
48
|
TextPartFlag,
|
|
49
49
|
} from 'treb-base-types';
|
|
50
50
|
|
|
51
|
-
import type {
|
|
52
|
-
Parser,
|
|
53
|
-
ExpressionUnit} from 'treb-parser';
|
|
51
|
+
import type { ExpressionUnit } from 'treb-parser';
|
|
54
52
|
import {
|
|
55
53
|
DecimalMarkType,
|
|
56
54
|
ArgumentSeparatorType,
|
|
@@ -66,7 +64,6 @@ import { SelectionRenderer } from '../render/selection-renderer';
|
|
|
66
64
|
import { TabBar } from './tab_bar';
|
|
67
65
|
import type { StatsEntry } from './tab_bar';
|
|
68
66
|
|
|
69
|
-
import { Sheet } from './sheet';
|
|
70
67
|
import { MockLayout } from '../layout/mock-layout';
|
|
71
68
|
import type { BaseLayout } from '../layout/base_layout';
|
|
72
69
|
import { TileRange } from '../layout/base_layout';
|
|
@@ -79,21 +76,24 @@ import { TileRange } from '../layout/base_layout';
|
|
|
79
76
|
|
|
80
77
|
import { GridLayout } from '../layout/grid_layout';
|
|
81
78
|
|
|
82
|
-
import type { GridSelection } from './grid_selection';
|
|
83
79
|
import { OverlayEditor } from '../editors/overlay_editor';
|
|
84
80
|
|
|
85
81
|
import { TileRenderer } from '../render/tile_renderer';
|
|
86
82
|
import type { GridEvent } from './grid_events';
|
|
87
83
|
import { ErrorCode } from './grid_events';
|
|
88
|
-
import type { LegacySerializedSheet } from './sheet_types';
|
|
89
|
-
// import { FormulaBar } from '../editors/formula_bar';
|
|
90
|
-
import { FormulaBar } from '../editors/formula_bar';
|
|
91
84
|
|
|
85
|
+
import type {
|
|
86
|
+
CompositeNamed,
|
|
87
|
+
DataModel,
|
|
88
|
+
GridSelection,
|
|
89
|
+
LegacySerializedSheet,
|
|
90
|
+
} from 'treb-data-model';
|
|
91
|
+
import { Annotation, type AnnotationData, Sheet } from 'treb-data-model';
|
|
92
|
+
|
|
93
|
+
import { FormulaBar } from '../editors/formula_bar';
|
|
92
94
|
import type { GridOptions } from './grid_options';
|
|
93
95
|
import { BorderConstants } from './border_constants';
|
|
94
|
-
import type { SerializeOptions } from './serialize_options';
|
|
95
96
|
import { UA } from '../util/ua';
|
|
96
|
-
import { Annotation, type AnnotationData } from './annotation';
|
|
97
97
|
import { Autocomplete } from '../editors/autocomplete';
|
|
98
98
|
|
|
99
99
|
import { MouseDrag } from './drag_mask';
|
|
@@ -109,8 +109,6 @@ import type {
|
|
|
109
109
|
import { CommandKey
|
|
110
110
|
} from './grid_command';
|
|
111
111
|
|
|
112
|
-
import type { DataModel, SerializedModel } from './data_model';
|
|
113
|
-
|
|
114
112
|
import { DOMContext } from 'treb-base-types';
|
|
115
113
|
import { GridBase } from './grid_base';
|
|
116
114
|
import type { SetRangeOptions } from './set_range_options';
|
|
@@ -891,7 +889,8 @@ export class Grid extends GridBase {
|
|
|
891
889
|
public FromImportData(
|
|
892
890
|
import_data: {
|
|
893
891
|
sheets: ImportedSheetData[],
|
|
894
|
-
names?: Record<string, string|number>,
|
|
892
|
+
// names?: Record<string, string|number>,
|
|
893
|
+
named?: CompositeNamed[],
|
|
895
894
|
active_tab?: number,
|
|
896
895
|
},
|
|
897
896
|
render = false,
|
|
@@ -969,14 +968,26 @@ export class Grid extends GridBase {
|
|
|
969
968
|
}
|
|
970
969
|
|
|
971
970
|
this.model.sheets.UpdateIndexes();
|
|
972
|
-
this.model.named_ranges.Reset();
|
|
973
|
-
this.model.named_expressions.clear();
|
|
974
971
|
|
|
972
|
+
this.model.named.Reset();
|
|
973
|
+
// this.model.named_ranges.Reset();
|
|
974
|
+
// this.model.named_expressions.clear();
|
|
975
|
+
|
|
976
|
+
console.info({IDX: import_data.named});
|
|
977
|
+
|
|
978
|
+
if (import_data.named) {
|
|
979
|
+
this.model.UnserializeComposite(import_data.named, this.active_sheet);
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
/*
|
|
975
983
|
if (import_data.names) {
|
|
976
984
|
|
|
985
|
+
console.info("IDN", { names: import_data.names })
|
|
986
|
+
|
|
977
987
|
for (const name of Object.keys(import_data.names)) {
|
|
978
988
|
|
|
979
|
-
const validated = this.model.
|
|
989
|
+
const validated = this.model.named.ValidateNamed(name);
|
|
990
|
+
|
|
980
991
|
if (!validated) {
|
|
981
992
|
console.warn(`invalid name: ${name}`, import_data.names[name]);
|
|
982
993
|
continue;
|
|
@@ -994,14 +1005,14 @@ export class Grid extends GridBase {
|
|
|
994
1005
|
const sheet_id = name_map[parse_result.expression.start.sheet || ''];
|
|
995
1006
|
if (sheet_id) {
|
|
996
1007
|
parse_result.expression.start.sheet_id = sheet_id;
|
|
997
|
-
this.model.
|
|
1008
|
+
this.model.named.SetNamedRange(validated, new Area(parse_result.expression.start, parse_result.expression.end));
|
|
998
1009
|
}
|
|
999
1010
|
}
|
|
1000
1011
|
else if (parse_result.expression.type === 'address') {
|
|
1001
1012
|
const sheet_id = name_map[parse_result.expression.sheet || ''];
|
|
1002
1013
|
if (sheet_id) {
|
|
1003
1014
|
parse_result.expression.sheet_id = sheet_id;
|
|
1004
|
-
this.model.
|
|
1015
|
+
this.model.named.SetNamedRange(validated, new Area(parse_result.expression));
|
|
1005
1016
|
}
|
|
1006
1017
|
}
|
|
1007
1018
|
else {
|
|
@@ -1022,13 +1033,16 @@ export class Grid extends GridBase {
|
|
|
1022
1033
|
}
|
|
1023
1034
|
return true;
|
|
1024
1035
|
});
|
|
1025
|
-
|
|
1036
|
+
|
|
1037
|
+
this.model.named.SetNamedExpression(validated, expr);
|
|
1038
|
+
|
|
1026
1039
|
}
|
|
1027
1040
|
}
|
|
1028
1041
|
}
|
|
1029
1042
|
}
|
|
1030
|
-
this.model.named_ranges.RebuildList();
|
|
1043
|
+
// this.model.named_ranges.RebuildList();
|
|
1031
1044
|
}
|
|
1045
|
+
*/
|
|
1032
1046
|
|
|
1033
1047
|
// FIXME: do we need to rebuild autocomplete here (A: yes)
|
|
1034
1048
|
// ...
|
|
@@ -1190,6 +1204,15 @@ export class Grid extends GridBase {
|
|
|
1190
1204
|
this.Repaint(true);
|
|
1191
1205
|
}
|
|
1192
1206
|
|
|
1207
|
+
/**
|
|
1208
|
+
* we need this method for split views
|
|
1209
|
+
*/
|
|
1210
|
+
public UpdateTabBar(): void {
|
|
1211
|
+
if (this.tab_bar) {
|
|
1212
|
+
this.tab_bar.Update();
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1193
1216
|
/**
|
|
1194
1217
|
* @param initial first call, from the grid Initialize() method
|
|
1195
1218
|
*/
|
|
@@ -1563,52 +1586,50 @@ export class Grid extends GridBase {
|
|
|
1563
1586
|
}
|
|
1564
1587
|
|
|
1565
1588
|
/**
|
|
1566
|
-
* set or clear name
|
|
1589
|
+
* set or clear name. optionally overwrite existing name. note that
|
|
1590
|
+
* you cannot overwrite function names, only existing named ranges/expressions.
|
|
1591
|
+
*
|
|
1592
|
+
* set name to refer to a range (named range) or expression/value (named
|
|
1593
|
+
* expression). range has priority if you set both (FIXME: make that impossible)
|
|
1594
|
+
*
|
|
1595
|
+
* note that expression here must be a valid expression in SL. if you want
|
|
1596
|
+
* to set a literal string, enclose it in double quotes (as you would when
|
|
1597
|
+
* using a string as an argument to a function).
|
|
1567
1598
|
*/
|
|
1568
|
-
public SetName(name: string, range?: ICellAddress | Area, expression?: string): void {
|
|
1599
|
+
public SetName(name: string, range?: ICellAddress | Area, expression?: string, scope?: number, overwrite = false): void {
|
|
1569
1600
|
|
|
1570
|
-
// console.info('setname', name, range, expression);
|
|
1601
|
+
// console.info('setname', name, range, expression, scope, overwrite);
|
|
1571
1602
|
|
|
1572
1603
|
// validate/translate name first
|
|
1573
1604
|
|
|
1574
|
-
const validated = this.model.
|
|
1605
|
+
const validated = this.model.named.ValidateNamed(name);
|
|
1575
1606
|
|
|
1576
1607
|
if (!validated) {
|
|
1577
1608
|
throw new Error('invalid name');
|
|
1578
1609
|
}
|
|
1579
1610
|
|
|
1580
|
-
|
|
1611
|
+
name = validated;
|
|
1581
1612
|
|
|
1582
|
-
//
|
|
1613
|
+
// check against functions. also an error if the name exists
|
|
1614
|
+
// but the overwrite flag is not set.
|
|
1583
1615
|
|
|
1584
|
-
const compare = name.trim().toUpperCase();
|
|
1585
1616
|
if (this.autocomplete_matcher) {
|
|
1586
|
-
for (const name of Object.keys(this.autocomplete_matcher.function_map)) {
|
|
1587
|
-
if (compare === name.toUpperCase()) {
|
|
1588
|
-
// const descriptor = this.autocomplete_matcher.function_map[name];
|
|
1589
|
-
|
|
1590
|
-
// hmmm... we're not actually setting this type
|
|
1591
|
-
// (DescriptorType.Function). it seems like we only
|
|
1592
|
-
// set the _other_ type. sloppy.
|
|
1593
1617
|
|
|
1618
|
+
const ac_entry = this.autocomplete_matcher.Get(name);
|
|
1619
|
+
if (ac_entry) {
|
|
1620
|
+
if (!ac_entry.named || !overwrite) {
|
|
1594
1621
|
if (range || expression) {
|
|
1595
1622
|
throw new Error('name already defined');
|
|
1596
1623
|
}
|
|
1597
|
-
|
|
1598
|
-
//if (descriptor.type !== DescriptorType.Token) {
|
|
1599
|
-
// throw new Error('invalid name');
|
|
1600
|
-
//}
|
|
1601
|
-
|
|
1602
|
-
break; // since we can't have two with the same name
|
|
1603
1624
|
}
|
|
1604
1625
|
}
|
|
1605
|
-
}
|
|
1606
|
-
|
|
1607
|
-
name = validated;
|
|
1608
1626
|
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1609
1629
|
const command: SetNameCommand = {
|
|
1610
1630
|
key: CommandKey.SetName,
|
|
1611
1631
|
name,
|
|
1632
|
+
scope,
|
|
1612
1633
|
};
|
|
1613
1634
|
|
|
1614
1635
|
if (range) {
|
|
@@ -1629,7 +1650,19 @@ export class Grid extends GridBase {
|
|
|
1629
1650
|
|
|
1630
1651
|
}
|
|
1631
1652
|
else if (expression) {
|
|
1653
|
+
|
|
1632
1654
|
const parse_result = this.parser.Parse(expression);
|
|
1655
|
+
|
|
1656
|
+
// there's a case we're missing here: if you pass a literal
|
|
1657
|
+
// string, not as a function, that should be interpreted as
|
|
1658
|
+
// a string. we still want to use the parser on functions
|
|
1659
|
+
// and literal types... how to distinguish?
|
|
1660
|
+
|
|
1661
|
+
// actually, check that: let's require strings to be quoted,
|
|
1662
|
+
// so they get interpreted as literals. if you want to do fancy
|
|
1663
|
+
// switching do that at a higher level.
|
|
1664
|
+
|
|
1665
|
+
// ...
|
|
1633
1666
|
|
|
1634
1667
|
// resolve sheet. otherwise we wind up with dangling
|
|
1635
1668
|
// references. NOTE: need to do this on import as well
|
|
@@ -1700,7 +1733,7 @@ export class Grid extends GridBase {
|
|
|
1700
1733
|
// should this persist, or should we only subscribe when we're active? (...)
|
|
1701
1734
|
// in theory, at least, it won't send any events unless something changes
|
|
1702
1735
|
|
|
1703
|
-
editor.Subscribe(
|
|
1736
|
+
editor.Subscribe(() => this.HighlightDependencies(editor.dependencies));
|
|
1704
1737
|
}
|
|
1705
1738
|
|
|
1706
1739
|
this.external_editor.AttachNodes(config.nodes, config.assume_formula ?? true);
|
|
@@ -2564,7 +2597,10 @@ export class Grid extends GridBase {
|
|
|
2564
2597
|
|
|
2565
2598
|
case 'identifier':
|
|
2566
2599
|
{
|
|
2567
|
-
|
|
2600
|
+
const named = this.model.GetName(parse_result.expression.name, this.active_sheet.id); // assuming it's in the active sheet? what if it's qualified?
|
|
2601
|
+
if (named?.type === 'range') {
|
|
2602
|
+
target_area = named.area;
|
|
2603
|
+
}
|
|
2568
2604
|
if (!target_area) {
|
|
2569
2605
|
if (!this.primary_selection.empty) {
|
|
2570
2606
|
this.SetName(parse_result.expression.name.toUpperCase(), this.primary_selection.area);
|
|
@@ -3886,7 +3922,7 @@ export class Grid extends GridBase {
|
|
|
3886
3922
|
type: 'cell-event',
|
|
3887
3923
|
data: {
|
|
3888
3924
|
type: 'hyperlink',
|
|
3889
|
-
|
|
3925
|
+
reference: link,
|
|
3890
3926
|
}
|
|
3891
3927
|
});
|
|
3892
3928
|
});
|
|
@@ -3939,17 +3975,6 @@ export class Grid extends GridBase {
|
|
|
3939
3975
|
|
|
3940
3976
|
}
|
|
3941
3977
|
|
|
3942
|
-
/*
|
|
3943
|
-
if (result.event) {
|
|
3944
|
-
Yield().then(() => {
|
|
3945
|
-
this.grid_events.Publish({
|
|
3946
|
-
type: 'cell-event',
|
|
3947
|
-
data: result.event,
|
|
3948
|
-
});
|
|
3949
|
-
});
|
|
3950
|
-
}
|
|
3951
|
-
*/
|
|
3952
|
-
|
|
3953
3978
|
return;
|
|
3954
3979
|
}
|
|
3955
3980
|
}
|
|
@@ -3977,7 +4002,7 @@ export class Grid extends GridBase {
|
|
|
3977
4002
|
y: move_event.offsetY - offset.y,
|
|
3978
4003
|
};
|
|
3979
4004
|
const testpoint = grid_rect.Clamp(point.x, point.y);
|
|
3980
|
-
const address = this.layout.PointToAddress_Grid(testpoint
|
|
4005
|
+
const address = this.layout.PointToAddress_Grid(testpoint);
|
|
3981
4006
|
|
|
3982
4007
|
const scroll_node = this.layout.scroll_reference_node;
|
|
3983
4008
|
|
|
@@ -4349,7 +4374,7 @@ export class Grid extends GridBase {
|
|
|
4349
4374
|
const data = this.active_sheet.CellData(selection.area.start);
|
|
4350
4375
|
const target = new Area(data.merge_area ? data.merge_area.start : selection.target);
|
|
4351
4376
|
|
|
4352
|
-
let label = this.model.
|
|
4377
|
+
let label = this.model.named.MatchSelection(selection.area, target);
|
|
4353
4378
|
|
|
4354
4379
|
if (!label) {
|
|
4355
4380
|
|
|
@@ -4375,16 +4400,16 @@ export class Grid extends GridBase {
|
|
|
4375
4400
|
// for now, we might update that in the future.
|
|
4376
4401
|
|
|
4377
4402
|
if (this.overlay_editor?.editing && this.overlay_editor.selecting) {
|
|
4378
|
-
this.overlay_editor.InsertReference(label
|
|
4403
|
+
this.overlay_editor.InsertReference(label);
|
|
4379
4404
|
}
|
|
4380
4405
|
else if (this.formula_bar && this.formula_bar.selecting) {
|
|
4381
|
-
this.formula_bar.InsertReference(label
|
|
4406
|
+
this.formula_bar.InsertReference(label);
|
|
4382
4407
|
}
|
|
4383
4408
|
else if (this.external_editor_config) {
|
|
4384
4409
|
|
|
4385
4410
|
if (this.external_editor?.active) {
|
|
4386
4411
|
this.external_editor.FocusEditor();
|
|
4387
|
-
this.external_editor.InsertReference(label
|
|
4412
|
+
this.external_editor.InsertReference(label);
|
|
4388
4413
|
}
|
|
4389
4414
|
|
|
4390
4415
|
if (this.external_editor_config.update) {
|
|
@@ -5338,8 +5363,11 @@ export class Grid extends GridBase {
|
|
|
5338
5363
|
break;
|
|
5339
5364
|
|
|
5340
5365
|
case 'identifier':
|
|
5341
|
-
|
|
5342
|
-
|
|
5366
|
+
{
|
|
5367
|
+
const named_range = this.model.GetName(unit.name, this.active_sheet.id); // FIXME: is this the correct sheet ref?
|
|
5368
|
+
if (named_range?.type === 'range') {
|
|
5369
|
+
unit.name = unit.name.toUpperCase();
|
|
5370
|
+
}
|
|
5343
5371
|
}
|
|
5344
5372
|
break;
|
|
5345
5373
|
|
|
@@ -6133,6 +6161,7 @@ export class Grid extends GridBase {
|
|
|
6133
6161
|
// be a rectangle) and one of those new cells might itself be merged.
|
|
6134
6162
|
// so we need to iterate. there's a lot of duplication here, though.
|
|
6135
6163
|
|
|
6164
|
+
// eslint-disable-next-line no-constant-condition
|
|
6136
6165
|
recheck_loop: while (true) {
|
|
6137
6166
|
for (const cell of this.active_sheet.cells.Iterate(real_area, false)) {
|
|
6138
6167
|
if (cell.merge_area && !real_area.ContainsArea(cell.merge_area)) {
|
|
@@ -6420,8 +6449,8 @@ export class Grid extends GridBase {
|
|
|
6420
6449
|
const target = new Area(data.merge_area ? data.merge_area.start : selection.target);
|
|
6421
6450
|
|
|
6422
6451
|
this.formula_bar.label =
|
|
6423
|
-
|
|
6424
|
-
|
|
6452
|
+
this.model.named.MatchSelection(selection.area, target)
|
|
6453
|
+
|| Area.CellAddressToLabel(target.start);
|
|
6425
6454
|
|
|
6426
6455
|
}
|
|
6427
6456
|
|
|
@@ -36,21 +36,24 @@
|
|
|
36
36
|
*/
|
|
37
37
|
|
|
38
38
|
import { EventSource } from 'treb-utils';
|
|
39
|
-
import type { DataModel, MacroFunction, SerializedModel, SerializedNamedExpression,
|
|
39
|
+
import type { DataModel, ConditionalFormat, // MacroFunction, SerializedModel, SerializedNamedExpression,
|
|
40
|
+
ViewModel } from 'treb-data-model';
|
|
41
|
+
|
|
40
42
|
import type { Parser, UnitAddress} from 'treb-parser';
|
|
41
|
-
import { type ExpressionUnit, IllegalSheetNameRegex, ParseCSV,
|
|
43
|
+
import { type ExpressionUnit, IllegalSheetNameRegex, ParseCSV, DecimalMarkType } from 'treb-parser';
|
|
42
44
|
import { Area, IsCellAddress, ValidationType, ValueType, DefaultTableSortOptions } from 'treb-base-types';
|
|
43
|
-
import type { ICellAddress, IArea, Cell, CellValue
|
|
44
|
-
|
|
45
|
+
import type { ICellAddress, IArea, Cell, CellValue, CellStyle, Table, TableSortOptions, TableTheme, Complex, PatchOptions as PatchAreaOptions } from 'treb-base-types';
|
|
46
|
+
|
|
47
|
+
import { Sheet, type SerializeOptions, type Annotation } from 'treb-data-model';
|
|
48
|
+
|
|
45
49
|
import type { FunctionDescriptor} from '../editors/autocomplete_matcher';
|
|
46
|
-
import { AutocompleteMatcher
|
|
50
|
+
import { AutocompleteMatcher } from '../editors/autocomplete_matcher';
|
|
47
51
|
import { NumberFormat, ValueParser } from 'treb-format';
|
|
48
52
|
|
|
49
53
|
import type { GridEvent } from './grid_events';
|
|
50
54
|
import { ErrorCode } from './grid_events';
|
|
51
55
|
import type { CommandRecord, DataValidationCommand, DuplicateSheetCommand, FreezeCommand, InsertColumnsCommand, InsertRowsCommand, ResizeColumnsCommand, ResizeRowsCommand, SelectCommand, SetRangeCommand, ShowSheetCommand, SortTableCommand } from './grid_command';
|
|
52
56
|
import { DefaultGridOptions, type GridOptions } from './grid_options';
|
|
53
|
-
import type { SerializeOptions } from './serialize_options';
|
|
54
57
|
|
|
55
58
|
import { BorderConstants } from './border_constants';
|
|
56
59
|
|
|
@@ -58,15 +61,18 @@ import { CommandKey } from './grid_command';
|
|
|
58
61
|
import type { Command, ActivateSheetCommand,
|
|
59
62
|
DeleteSheetCommand, UpdateBordersCommand, SheetSelection } from './grid_command';
|
|
60
63
|
import type { UpdateFlags } from './update_flags';
|
|
61
|
-
import type { FreezePane, LegacySerializedSheet } from '
|
|
62
|
-
import type { Annotation } from './annotation';
|
|
64
|
+
import type { FreezePane, LegacySerializedSheet } from 'treb-data-model';
|
|
63
65
|
import type { ClipboardCellData } from './clipboard_data';
|
|
64
|
-
import type { ConditionalFormat } from './conditional_format';
|
|
65
66
|
|
|
66
67
|
interface PatchOptions extends PatchAreaOptions {
|
|
67
68
|
sheet: Sheet;
|
|
68
69
|
}
|
|
69
70
|
|
|
71
|
+
// this is an assert, bascially, for completeness. we could probably
|
|
72
|
+
// resolve the eslint issue (there's no type option) but not sure it's
|
|
73
|
+
// useful to do so
|
|
74
|
+
|
|
75
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
70
76
|
const AssertNever = (value: never) => {
|
|
71
77
|
console.error('invalid case');
|
|
72
78
|
};
|
|
@@ -666,6 +672,7 @@ export class GridBase {
|
|
|
666
672
|
*
|
|
667
673
|
* this is non-UI; specialization should handle the UI part
|
|
668
674
|
*/
|
|
675
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
669
676
|
public UpdateSheets(data: LegacySerializedSheet[], render = false, activate_sheet?: number | string): void {
|
|
670
677
|
|
|
671
678
|
Sheet.Reset(); // reset ID generation
|
|
@@ -719,24 +726,43 @@ export class GridBase {
|
|
|
719
726
|
*/
|
|
720
727
|
public SetAutocompleteFunctions(functions: FunctionDescriptor[]): void {
|
|
721
728
|
|
|
722
|
-
// why does iterable support forEach but not map?
|
|
723
|
-
|
|
724
729
|
const expressions: FunctionDescriptor[] = [];
|
|
730
|
+
|
|
731
|
+
for (const entry of this.model.named.list) {
|
|
732
|
+
expressions.push({
|
|
733
|
+
name: entry.name,
|
|
734
|
+
named: true,
|
|
735
|
+
type: 'token',
|
|
736
|
+
});
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
/*
|
|
725
740
|
for (const name of this.model.named_expressions.keys()) {
|
|
726
741
|
expressions.push({
|
|
727
|
-
name,
|
|
742
|
+
name,
|
|
743
|
+
named: true,
|
|
744
|
+
type: 'token',
|
|
728
745
|
});
|
|
729
746
|
}
|
|
747
|
+
*/
|
|
730
748
|
|
|
749
|
+
const consolidated= functions.slice(0).concat(expressions);
|
|
750
|
+
|
|
751
|
+
/*
|
|
731
752
|
const consolidated = functions.slice(0).concat(
|
|
732
753
|
this.model.named_ranges.List().map((named_range) => {
|
|
733
|
-
return {
|
|
754
|
+
return {
|
|
755
|
+
name: named_range.name,
|
|
756
|
+
named: true,
|
|
757
|
+
type: 'token'
|
|
758
|
+
};
|
|
734
759
|
}),
|
|
735
760
|
expressions,
|
|
736
761
|
);
|
|
762
|
+
*/
|
|
737
763
|
|
|
738
|
-
//this.autocomplete_matcher.SetFunctions(functions);
|
|
739
764
|
this.autocomplete_matcher.SetFunctions(consolidated);
|
|
765
|
+
|
|
740
766
|
}
|
|
741
767
|
|
|
742
768
|
public ResetMetadata(): void {
|
|
@@ -813,8 +839,9 @@ export class GridBase {
|
|
|
813
839
|
|
|
814
840
|
Sheet.Reset();
|
|
815
841
|
this.UpdateSheets([], true);
|
|
816
|
-
|
|
817
|
-
this.model.
|
|
842
|
+
|
|
843
|
+
this.model.named.Reset();
|
|
844
|
+
|
|
818
845
|
this.model.macro_functions.clear(); // = {};
|
|
819
846
|
this.model.tables.clear();
|
|
820
847
|
|
|
@@ -839,7 +866,7 @@ export class GridBase {
|
|
|
839
866
|
return false;
|
|
840
867
|
}
|
|
841
868
|
|
|
842
|
-
let valid = true;
|
|
869
|
+
// let valid = true;
|
|
843
870
|
|
|
844
871
|
for (const cell of sheet.cells.Iterate(area)) {
|
|
845
872
|
|
|
@@ -885,9 +912,9 @@ export class GridBase {
|
|
|
885
912
|
});
|
|
886
913
|
*/
|
|
887
914
|
|
|
888
|
-
if (!valid) {
|
|
889
|
-
|
|
890
|
-
}
|
|
915
|
+
// if (!valid) {
|
|
916
|
+
// return false;
|
|
917
|
+
// }
|
|
891
918
|
|
|
892
919
|
}
|
|
893
920
|
return true;
|
|
@@ -985,7 +1012,7 @@ export class GridBase {
|
|
|
985
1012
|
if (i === command.index || sheet.id === command.id || sheet.name.toLowerCase() === named_sheet) {
|
|
986
1013
|
is_active = (sheet === this.active_sheet);
|
|
987
1014
|
|
|
988
|
-
this.model.
|
|
1015
|
+
this.model.named.RemoveRangesForSheet(sheet.id);
|
|
989
1016
|
target_name = sheet.name;
|
|
990
1017
|
|
|
991
1018
|
index = i;
|
|
@@ -1917,6 +1944,7 @@ export class GridBase {
|
|
|
1917
1944
|
// have to have a proper area. there's no case where we would
|
|
1918
1945
|
// want to add it. so we only handle the area case.
|
|
1919
1946
|
|
|
1947
|
+
// eslint-disable-next-line no-fallthrough
|
|
1920
1948
|
case CommandKey.RemoveConditionalFormat:
|
|
1921
1949
|
|
|
1922
1950
|
if (command.area) {
|
|
@@ -2515,7 +2543,7 @@ export class GridBase {
|
|
|
2515
2543
|
return;
|
|
2516
2544
|
}
|
|
2517
2545
|
|
|
2518
|
-
let error = false;
|
|
2546
|
+
// let error = false;
|
|
2519
2547
|
area = sheet.RealArea(area); // collapse
|
|
2520
2548
|
|
|
2521
2549
|
for (const cell of sheet.cells.Iterate(area)) {
|
|
@@ -2554,13 +2582,17 @@ export class GridBase {
|
|
|
2554
2582
|
}
|
|
2555
2583
|
}
|
|
2556
2584
|
|
|
2585
|
+
/*
|
|
2557
2586
|
if (error) {
|
|
2558
2587
|
this.Error(ErrorCode.array); // `You can't change part of an array.`
|
|
2559
2588
|
}
|
|
2560
2589
|
else {
|
|
2561
2590
|
sheet.ClearArea(area);
|
|
2562
2591
|
}
|
|
2563
|
-
|
|
2592
|
+
*/
|
|
2593
|
+
|
|
2594
|
+
sheet.ClearArea(area);
|
|
2595
|
+
|
|
2564
2596
|
}
|
|
2565
2597
|
|
|
2566
2598
|
/**
|
|
@@ -2678,6 +2710,7 @@ export class GridBase {
|
|
|
2678
2710
|
*
|
|
2679
2711
|
* @param command
|
|
2680
2712
|
*/
|
|
2713
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2681
2714
|
protected SelectInternal(command: SelectCommand) {
|
|
2682
2715
|
// does nothing
|
|
2683
2716
|
}
|
|
@@ -2942,7 +2975,7 @@ export class GridBase {
|
|
|
2942
2975
|
}
|
|
2943
2976
|
|
|
2944
2977
|
|
|
2945
|
-
this.model.
|
|
2978
|
+
this.model.named.PatchNamedRanges(target_sheet.id, 0, 0, command.before_row, command.count);
|
|
2946
2979
|
|
|
2947
2980
|
const target_sheet_name = target_sheet.name.toLowerCase();
|
|
2948
2981
|
|
|
@@ -3284,7 +3317,7 @@ export class GridBase {
|
|
|
3284
3317
|
}
|
|
3285
3318
|
|
|
3286
3319
|
|
|
3287
|
-
this.model.
|
|
3320
|
+
this.model.named.PatchNamedRanges(target_sheet.id, command.before_column, command.count, 0, 0);
|
|
3288
3321
|
|
|
3289
3322
|
// FIXME: we need an event here?
|
|
3290
3323
|
|
|
@@ -3929,7 +3962,7 @@ export class GridBase {
|
|
|
3929
3962
|
sheet.UpdateCellStyle(address, {
|
|
3930
3963
|
indent: Math.max(0, (style.indent || 0) + command.delta),
|
|
3931
3964
|
}, true);
|
|
3932
|
-
}
|
|
3965
|
+
}
|
|
3933
3966
|
}
|
|
3934
3967
|
|
|
3935
3968
|
if (sheet === this.active_sheet) {
|
|
@@ -4011,42 +4044,25 @@ export class GridBase {
|
|
|
4011
4044
|
// FOR THE TIME BEING we're going to add that restriction to
|
|
4012
4045
|
// the calling function, which (atm) is the only way to get here.
|
|
4013
4046
|
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
|
|
4047
|
+
{
|
|
4048
|
+
const ac_token: FunctionDescriptor = { type: 'token', named: true, name: command.name, scope: command.scope };
|
|
4049
|
+
if (command.area || command.expression) {
|
|
4050
|
+
if (command.area) {
|
|
4051
|
+
this.model.named.SetNamedRange(command.name, new Area(command.area.start, command.area.end), command.scope);
|
|
4052
|
+
}
|
|
4053
|
+
else if (command.expression) {
|
|
4054
|
+
this.model.named.SetNamedExpression(command.name, command.expression, command.scope);
|
|
4055
|
+
}
|
|
4056
|
+
this.autocomplete_matcher.AddFunctions(ac_token);
|
|
4057
|
+
}
|
|
4058
|
+
else {
|
|
4059
|
+
this.model.named.ClearName(command.name, command.scope);
|
|
4060
|
+
this.autocomplete_matcher.RemoveFunctions(ac_token);
|
|
4061
|
+
}
|
|
4020
4062
|
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
this.autocomplete_matcher.AddFunctions({
|
|
4024
|
-
type: DescriptorType.Token,
|
|
4025
|
-
name: command.name,
|
|
4026
|
-
});
|
|
4027
|
-
}
|
|
4028
|
-
else if (command.expression) {
|
|
4029
|
-
this.model.named_ranges.ClearName(command.name);
|
|
4030
|
-
this.model.named_expressions.set(command.name, command.expression);
|
|
4031
|
-
this.autocomplete_matcher.AddFunctions({
|
|
4032
|
-
type: DescriptorType.Token,
|
|
4033
|
-
name: command.name,
|
|
4034
|
-
});
|
|
4035
|
-
}
|
|
4036
|
-
else {
|
|
4037
|
-
this.model.named_ranges.ClearName(command.name);
|
|
4038
|
-
//if (this.model.named_expressions[command.name]) {
|
|
4039
|
-
// delete this.model.named_expressions[command.name];
|
|
4040
|
-
//}
|
|
4041
|
-
this.model.named_expressions.delete(command.name);
|
|
4042
|
-
|
|
4043
|
-
this.autocomplete_matcher.RemoveFunctions({
|
|
4044
|
-
type: DescriptorType.Token,
|
|
4045
|
-
name: command.name,
|
|
4046
|
-
});
|
|
4063
|
+
flags.structure_event = true;
|
|
4064
|
+
flags.structure_rebuild_required = true;
|
|
4047
4065
|
}
|
|
4048
|
-
flags.structure_event = true;
|
|
4049
|
-
flags.structure_rebuild_required = true;
|
|
4050
4066
|
break;
|
|
4051
4067
|
|
|
4052
4068
|
case CommandKey.UpdateBorders:
|
|
@@ -19,10 +19,10 @@
|
|
|
19
19
|
*
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
import type { ICellAddress, IArea,
|
|
22
|
+
import type { ICellAddress, IArea, CellStyle, Color, CellValue, Table, TableSortType, TableTheme } from 'treb-base-types';
|
|
23
23
|
import type { ExpressionUnit } from 'treb-parser';
|
|
24
24
|
import type { BorderConstants } from './border_constants';
|
|
25
|
-
import type { ConditionalFormat } from '
|
|
25
|
+
import type { ConditionalFormat } from 'treb-data-model';
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* switching to an exec-command based model, so we can serialize
|
|
@@ -220,6 +220,7 @@ export interface SetNameCommand {
|
|
|
220
220
|
name: string;
|
|
221
221
|
area?: IArea;
|
|
222
222
|
expression?: ExpressionUnit;
|
|
223
|
+
scope?: number;
|
|
223
224
|
}
|
|
224
225
|
|
|
225
226
|
export interface DataValidationCommand {
|
|
@@ -19,11 +19,8 @@
|
|
|
19
19
|
*
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
import type { GridSelection } from '
|
|
23
|
-
import type { Annotation } from './annotation';
|
|
24
|
-
import type { Sheet } from './sheet';
|
|
22
|
+
import type { Annotation, GridSelection, Sheet } from 'treb-data-model';
|
|
25
23
|
import type { Area } from 'treb-base-types';
|
|
26
|
-
import type { ConditionalFormat } from './conditional_format';
|
|
27
24
|
|
|
28
25
|
export enum ErrorCode {
|
|
29
26
|
|
|
@@ -95,9 +92,18 @@ export interface AnnotationEvent {
|
|
|
95
92
|
event?: 'move'|'resize'|'create'|'delete'|'update';
|
|
96
93
|
}
|
|
97
94
|
|
|
95
|
+
export interface HyperlinkCellEventData {
|
|
96
|
+
type: 'hyperlink';
|
|
97
|
+
reference: string;
|
|
98
|
+
}
|
|
99
|
+
|
|
98
100
|
export interface CellEvent {
|
|
99
|
-
type: 'cell-event'
|
|
100
|
-
|
|
101
|
+
type: 'cell-event';
|
|
102
|
+
|
|
103
|
+
// theoretically we're going to extend this with additional types,
|
|
104
|
+
// but for now it's only used for hyperlinks.
|
|
105
|
+
|
|
106
|
+
data?: HyperlinkCellEventData;
|
|
101
107
|
}
|
|
102
108
|
|
|
103
109
|
export interface DataEvent {
|