@trebco/treb 23.6.2 → 25.0.0-rc1
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/.eslintignore +8 -0
- package/.eslintrc.js +164 -0
- package/README-shadow-DOM.md +88 -0
- package/README.md +37 -130
- package/api-config.json +29 -0
- package/api-generator/api-generator-types.ts +82 -0
- package/api-generator/api-generator.ts +1172 -0
- package/api-generator/package.json +3 -0
- package/build/treb-spreadsheet.mjs +14 -0
- package/{treb.d.ts → build/treb.d.ts} +293 -299
- package/esbuild-custom-element.mjs +336 -0
- package/esbuild.js +305 -0
- package/package.json +43 -14
- package/treb-base-types/package.json +5 -0
- package/treb-base-types/src/api_types.ts +36 -0
- package/treb-base-types/src/area.ts +583 -0
- package/treb-base-types/src/basic_types.ts +45 -0
- package/treb-base-types/src/cell.ts +612 -0
- package/treb-base-types/src/cells.ts +1066 -0
- package/treb-base-types/src/color.ts +124 -0
- package/treb-base-types/src/import.ts +71 -0
- package/treb-base-types/src/index-standalone.ts +29 -0
- package/treb-base-types/src/index.ts +42 -0
- package/treb-base-types/src/layout.ts +47 -0
- package/treb-base-types/src/localization.ts +187 -0
- package/treb-base-types/src/rectangle.ts +145 -0
- package/treb-base-types/src/render_text.ts +72 -0
- package/treb-base-types/src/style.ts +545 -0
- package/treb-base-types/src/table.ts +109 -0
- package/treb-base-types/src/text_part.ts +54 -0
- package/treb-base-types/src/theme.ts +608 -0
- package/treb-base-types/src/union.ts +152 -0
- package/treb-base-types/src/value-type.ts +164 -0
- package/treb-base-types/style/resizable.css +59 -0
- package/treb-calculator/modern.tsconfig.json +11 -0
- package/treb-calculator/package.json +5 -0
- package/treb-calculator/src/calculator.ts +2546 -0
- package/treb-calculator/src/complex-math.ts +558 -0
- package/treb-calculator/src/dag/array-vertex.ts +198 -0
- package/treb-calculator/src/dag/graph.ts +951 -0
- package/treb-calculator/src/dag/leaf_vertex.ts +118 -0
- package/treb-calculator/src/dag/spreadsheet_vertex.ts +327 -0
- package/treb-calculator/src/dag/spreadsheet_vertex_base.ts +44 -0
- package/treb-calculator/src/dag/vertex.ts +352 -0
- package/treb-calculator/src/descriptors.ts +162 -0
- package/treb-calculator/src/expression-calculator.ts +1069 -0
- package/treb-calculator/src/function-error.ts +103 -0
- package/treb-calculator/src/function-library.ts +103 -0
- package/treb-calculator/src/functions/base-functions.ts +1214 -0
- package/treb-calculator/src/functions/checkbox.ts +164 -0
- package/treb-calculator/src/functions/complex-functions.ts +253 -0
- package/treb-calculator/src/functions/finance-functions.ts +399 -0
- package/treb-calculator/src/functions/information-functions.ts +102 -0
- package/treb-calculator/src/functions/matrix-functions.ts +182 -0
- package/treb-calculator/src/functions/sparkline.ts +335 -0
- package/treb-calculator/src/functions/statistics-functions.ts +350 -0
- package/treb-calculator/src/functions/text-functions.ts +298 -0
- package/treb-calculator/src/index.ts +27 -0
- package/treb-calculator/src/notifier-types.ts +59 -0
- package/treb-calculator/src/primitives.ts +428 -0
- package/treb-calculator/src/utilities.ts +305 -0
- package/treb-charts/package.json +5 -0
- package/treb-charts/src/chart-functions.ts +156 -0
- package/treb-charts/src/chart-types.ts +230 -0
- package/treb-charts/src/chart.ts +1288 -0
- package/treb-charts/src/index.ts +24 -0
- package/treb-charts/src/main.ts +37 -0
- package/treb-charts/src/rectangle.ts +52 -0
- package/treb-charts/src/renderer.ts +1841 -0
- package/treb-charts/src/util.ts +122 -0
- package/treb-charts/style/charts.scss +221 -0
- package/treb-charts/style/old-charts.scss +250 -0
- package/treb-embed/markup/layout.html +137 -0
- package/treb-embed/markup/toolbar.html +175 -0
- package/treb-embed/modern.tsconfig.json +25 -0
- package/treb-embed/src/custom-element/content-types.d.ts +18 -0
- package/treb-embed/src/custom-element/global.d.ts +11 -0
- package/treb-embed/src/custom-element/spreadsheet-constructor.ts +1227 -0
- package/treb-embed/src/custom-element/treb-global.ts +44 -0
- package/treb-embed/src/custom-element/treb-spreadsheet-element.ts +52 -0
- package/treb-embed/src/embedded-spreadsheet.ts +5362 -0
- package/treb-embed/src/index.ts +16 -0
- package/treb-embed/src/language-model.ts +41 -0
- package/treb-embed/src/options.ts +320 -0
- package/treb-embed/src/progress-dialog.ts +228 -0
- package/treb-embed/src/selection-state.ts +16 -0
- package/treb-embed/src/spinner.ts +42 -0
- package/treb-embed/src/toolbar-message.ts +96 -0
- package/treb-embed/src/types.ts +167 -0
- package/treb-embed/style/autocomplete.scss +103 -0
- package/treb-embed/style/dark-theme.scss +114 -0
- package/treb-embed/style/defaults.scss +36 -0
- package/treb-embed/style/dialog.scss +181 -0
- package/treb-embed/style/dropdown-select.scss +101 -0
- package/treb-embed/style/formula-bar.scss +193 -0
- package/treb-embed/style/grid.scss +374 -0
- package/treb-embed/style/layout.scss +424 -0
- package/treb-embed/style/mouse-mask.scss +67 -0
- package/treb-embed/style/note.scss +92 -0
- package/treb-embed/style/overlay-editor.scss +102 -0
- package/treb-embed/style/spinner.scss +92 -0
- package/treb-embed/style/tab-bar.scss +228 -0
- package/treb-embed/style/table.scss +80 -0
- package/treb-embed/style/theme-defaults.scss +444 -0
- package/treb-embed/style/toolbar.scss +416 -0
- package/treb-embed/style/tooltip.scss +68 -0
- package/treb-embed/style/treb-icons.scss +130 -0
- package/treb-embed/style/treb-spreadsheet-element.scss +20 -0
- package/treb-embed/style/z-index.scss +43 -0
- package/treb-export/docs/charts.md +68 -0
- package/treb-export/modern.tsconfig.json +19 -0
- package/treb-export/package.json +4 -0
- package/treb-export/src/address-type.ts +77 -0
- package/treb-export/src/base-template.ts +22 -0
- package/treb-export/src/column-width.ts +85 -0
- package/treb-export/src/drawing2/chart-template-components2.ts +389 -0
- package/treb-export/src/drawing2/chart2.ts +282 -0
- package/treb-export/src/drawing2/column-chart-template2.ts +521 -0
- package/treb-export/src/drawing2/donut-chart-template2.ts +296 -0
- package/treb-export/src/drawing2/drawing2.ts +355 -0
- package/treb-export/src/drawing2/embedded-image.ts +71 -0
- package/treb-export/src/drawing2/scatter-chart-template2.ts +555 -0
- package/treb-export/src/export-worker/export-worker.ts +99 -0
- package/treb-export/src/export-worker/index-modern.ts +22 -0
- package/treb-export/src/export2.ts +2204 -0
- package/treb-export/src/import2.ts +882 -0
- package/treb-export/src/relationship.ts +36 -0
- package/treb-export/src/shared-strings2.ts +128 -0
- package/treb-export/src/template-2.ts +22 -0
- package/treb-export/src/unescape_xml.ts +47 -0
- package/treb-export/src/workbook-sheet2.ts +182 -0
- package/treb-export/src/workbook-style2.ts +1285 -0
- package/treb-export/src/workbook-theme2.ts +88 -0
- package/treb-export/src/workbook2.ts +491 -0
- package/treb-export/src/xml-utils.ts +201 -0
- package/treb-export/template/base/[Content_Types].xml +2 -0
- package/treb-export/template/base/_rels/.rels +2 -0
- package/treb-export/template/base/docProps/app.xml +2 -0
- package/treb-export/template/base/docProps/core.xml +12 -0
- package/treb-export/template/base/xl/_rels/workbook.xml.rels +2 -0
- package/treb-export/template/base/xl/sharedStrings.xml +2 -0
- package/treb-export/template/base/xl/styles.xml +2 -0
- package/treb-export/template/base/xl/theme/theme1.xml +2 -0
- package/treb-export/template/base/xl/workbook.xml +2 -0
- package/treb-export/template/base/xl/worksheets/sheet1.xml +2 -0
- package/treb-export/template/base.xlsx +0 -0
- package/treb-format/package.json +8 -0
- package/treb-format/src/format.test.ts +213 -0
- package/treb-format/src/format.ts +942 -0
- package/treb-format/src/format_cache.ts +199 -0
- package/treb-format/src/format_parser.ts +723 -0
- package/treb-format/src/index.ts +25 -0
- package/treb-format/src/number_format_section.ts +100 -0
- package/treb-format/src/value_parser.ts +337 -0
- package/treb-grid/package.json +5 -0
- package/treb-grid/src/editors/autocomplete.ts +394 -0
- package/treb-grid/src/editors/autocomplete_matcher.ts +260 -0
- package/treb-grid/src/editors/formula_bar.ts +473 -0
- package/treb-grid/src/editors/formula_editor_base.ts +910 -0
- package/treb-grid/src/editors/overlay_editor.ts +511 -0
- package/treb-grid/src/index.ts +37 -0
- package/treb-grid/src/layout/base_layout.ts +2618 -0
- package/treb-grid/src/layout/grid_layout.ts +299 -0
- package/treb-grid/src/layout/rectangle_cache.ts +86 -0
- package/treb-grid/src/render/selection-renderer.ts +414 -0
- package/treb-grid/src/render/svg_header_overlay.ts +93 -0
- package/treb-grid/src/render/svg_selection_block.ts +187 -0
- package/treb-grid/src/render/tile_renderer.ts +2122 -0
- package/treb-grid/src/types/annotation.ts +216 -0
- package/treb-grid/src/types/border_constants.ts +34 -0
- package/treb-grid/src/types/clipboard_data.ts +31 -0
- package/treb-grid/src/types/data_model.ts +334 -0
- package/treb-grid/src/types/drag_mask.ts +81 -0
- package/treb-grid/src/types/grid.ts +7743 -0
- package/treb-grid/src/types/grid_base.ts +3644 -0
- package/treb-grid/src/types/grid_command.ts +470 -0
- package/treb-grid/src/types/grid_events.ts +124 -0
- package/treb-grid/src/types/grid_options.ts +97 -0
- package/treb-grid/src/types/grid_selection.ts +60 -0
- package/treb-grid/src/types/named_range.ts +369 -0
- package/treb-grid/src/types/scale-control.ts +202 -0
- package/treb-grid/src/types/serialize_options.ts +72 -0
- package/treb-grid/src/types/set_range_options.ts +52 -0
- package/treb-grid/src/types/sheet.ts +3099 -0
- package/treb-grid/src/types/sheet_types.ts +95 -0
- package/treb-grid/src/types/tab_bar.ts +464 -0
- package/treb-grid/src/types/tile.ts +59 -0
- package/treb-grid/src/types/update_flags.ts +75 -0
- package/treb-grid/src/util/dom_utilities.ts +44 -0
- package/treb-grid/src/util/fontmetrics2.ts +179 -0
- package/treb-grid/src/util/ua.ts +104 -0
- package/treb-logo.svg +18 -0
- package/treb-parser/package.json +5 -0
- package/treb-parser/src/csv-parser.ts +122 -0
- package/treb-parser/src/index.ts +25 -0
- package/treb-parser/src/md-parser.ts +526 -0
- package/treb-parser/src/parser-types.ts +397 -0
- package/treb-parser/src/parser.test.ts +298 -0
- package/treb-parser/src/parser.ts +2673 -0
- package/treb-utils/package.json +5 -0
- package/treb-utils/src/dispatch.ts +57 -0
- package/treb-utils/src/event_source.ts +147 -0
- package/treb-utils/src/ievent_source.ts +33 -0
- package/treb-utils/src/index.ts +31 -0
- package/treb-utils/src/measurement.ts +174 -0
- package/treb-utils/src/resizable.ts +160 -0
- package/treb-utils/src/scale.ts +137 -0
- package/treb-utils/src/serialize_html.ts +124 -0
- package/treb-utils/src/template.ts +70 -0
- package/treb-utils/src/validate_uri.ts +61 -0
- package/tsconfig.json +10 -0
- package/tsproject.json +30 -0
- package/util/license-plugin-esbuild.js +86 -0
- package/util/list-css-vars.sh +46 -0
- package/README-esm.md +0 -37
- package/treb-bundle.css +0 -2
- package/treb-bundle.mjs +0 -15
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of TREB.
|
|
3
|
+
*
|
|
4
|
+
* TREB is free software: you can redistribute it and/or modify it under the
|
|
5
|
+
* terms of the GNU General Public License as published by the Free Software
|
|
6
|
+
* Foundation, either version 3 of the License, or (at your option) any
|
|
7
|
+
* later version.
|
|
8
|
+
*
|
|
9
|
+
* TREB is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
10
|
+
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
11
|
+
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
12
|
+
* details.
|
|
13
|
+
*
|
|
14
|
+
* You should have received a copy of the GNU General Public License along
|
|
15
|
+
* with TREB. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
*
|
|
17
|
+
* Copyright 2022-2023 trebco, llc.
|
|
18
|
+
* info@treb.app
|
|
19
|
+
*
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { Rectangle, ICellAddress, AnnotationLayout } from 'treb-base-types';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* new annotation class. annotations are arbitrary content
|
|
26
|
+
* inserted into the sheet, using a floating div element. the
|
|
27
|
+
* class is serialized with the sheet, so the caller can recreate
|
|
28
|
+
* the content if desired.
|
|
29
|
+
*
|
|
30
|
+
* because there's an element of layout involved, callers should
|
|
31
|
+
* interact with annotations through the grid class rather than the
|
|
32
|
+
* sheet.
|
|
33
|
+
*
|
|
34
|
+
* we are redesigning layout so that instead of a rectangle, in
|
|
35
|
+
* coordinate space, annotations use extents and offsets in cell space.
|
|
36
|
+
* so layout should now have a TL cell and a BR cell plus offsets for
|
|
37
|
+
* each. Offset is implemented as a % of the given cell, so offsets are
|
|
38
|
+
* inverted in the TL/BR cells.
|
|
39
|
+
*
|
|
40
|
+
* UPDATE: actually while the inverted BR offset makes intuitive sense,
|
|
41
|
+
* it doesn't make technical sense -- easier to always calcluate offsets
|
|
42
|
+
* in the same direction. so offsets are always positive.
|
|
43
|
+
*
|
|
44
|
+
* we'll leave the old extent in there (for now, at least) to prevent
|
|
45
|
+
* any unintended consequences.
|
|
46
|
+
*
|
|
47
|
+
* UPDATE: adding a view interface for view-specific data. this is prep
|
|
48
|
+
* for supporting annotations in split views; we have to change how we
|
|
49
|
+
* manage nodes and callbacks.
|
|
50
|
+
*
|
|
51
|
+
*/
|
|
52
|
+
|
|
53
|
+
let key_generator = 100;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* moving view-specific data into a separate interface to support split.
|
|
57
|
+
* nothing in view is serialized.
|
|
58
|
+
*/
|
|
59
|
+
export interface ViewData {
|
|
60
|
+
|
|
61
|
+
/** flag indicating we have inflated this. not serialized */
|
|
62
|
+
inflated?: boolean;
|
|
63
|
+
|
|
64
|
+
/** if function exists, will be called when the annotation is resized */
|
|
65
|
+
resize_callback?: () => void;
|
|
66
|
+
|
|
67
|
+
/** if function exists, will be called when the annotation needs to update */
|
|
68
|
+
update_callback?: () => void;
|
|
69
|
+
|
|
70
|
+
/** layout node */
|
|
71
|
+
node?: HTMLDivElement;
|
|
72
|
+
|
|
73
|
+
/** content node */
|
|
74
|
+
content_node?: HTMLDivElement;
|
|
75
|
+
|
|
76
|
+
/** view-specific dirty flag */
|
|
77
|
+
dirty?: boolean;
|
|
78
|
+
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export class Annotation {
|
|
82
|
+
|
|
83
|
+
public get key(): number { return this.key_; }
|
|
84
|
+
|
|
85
|
+
/** coordinates, in sheet space */
|
|
86
|
+
public rect?: Rectangle;
|
|
87
|
+
|
|
88
|
+
// public get rect(): Rectangle|undefined { return this.rect_; }
|
|
89
|
+
|
|
90
|
+
/** display coordinates, possibly scaled. not persisted. */
|
|
91
|
+
public scaled_rect?: Rectangle;
|
|
92
|
+
|
|
93
|
+
/** the new layout, persisted and takes preference over the old one */
|
|
94
|
+
public layout?: AnnotationLayout;
|
|
95
|
+
|
|
96
|
+
/** opaque data. this is serialized, so it's persistent data */
|
|
97
|
+
public data: any = {};
|
|
98
|
+
|
|
99
|
+
// opaque string which will be added to the class of any containing node
|
|
100
|
+
// public class_name?: string;
|
|
101
|
+
|
|
102
|
+
/** type, for filtering. ensure a value */
|
|
103
|
+
public type = '';
|
|
104
|
+
|
|
105
|
+
/** also opaque data, but not serialized. */
|
|
106
|
+
public temp: any = {};
|
|
107
|
+
|
|
108
|
+
/* * flag indicating we have inflated this. not serialized */
|
|
109
|
+
// public inflated = false;
|
|
110
|
+
|
|
111
|
+
/* * if function exists, will be called when the annotation is resized */
|
|
112
|
+
// public resize_callback?: () => void;
|
|
113
|
+
|
|
114
|
+
/* * if function exists, will be called when the annotation needs to update */
|
|
115
|
+
// public update_callback?: () => void;
|
|
116
|
+
|
|
117
|
+
/** annotation can be resized. this is advisory, for UI */
|
|
118
|
+
public resizable = true;
|
|
119
|
+
|
|
120
|
+
/** annotation can be moved. this is advisory, for UI */
|
|
121
|
+
public movable = true;
|
|
122
|
+
|
|
123
|
+
/** annotation can be removed/deleted. this is advisory, for UI */
|
|
124
|
+
public removable = true;
|
|
125
|
+
|
|
126
|
+
/** annotation can be selected. this is advisory, for UI */
|
|
127
|
+
public selectable = true;
|
|
128
|
+
|
|
129
|
+
/** move when resizing/inserting rows/columns */
|
|
130
|
+
public move_with_cells = true;
|
|
131
|
+
|
|
132
|
+
/** resize when resizing/inserting rows/columns */
|
|
133
|
+
public resize_with_cells = true;
|
|
134
|
+
|
|
135
|
+
/* * layout node, obviously not serialized */
|
|
136
|
+
// public node?: HTMLDivElement;
|
|
137
|
+
|
|
138
|
+
/* * content node */
|
|
139
|
+
// public content_node?: HTMLDivElement;
|
|
140
|
+
|
|
141
|
+
public view: ViewData[] = [];
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* advisory, meaning we probably need an update if there's an opportunity.
|
|
145
|
+
* only advisory and not persisted.
|
|
146
|
+
*/
|
|
147
|
+
public dirty?: boolean;
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* optional formula. the formula will be updated on structure events
|
|
151
|
+
* (insert/delete row/column).
|
|
152
|
+
*/
|
|
153
|
+
public formula = '';
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* extent, useful for exporting. we could probably serialize this,
|
|
157
|
+
* just be sure to clear it when layout changes so it will be
|
|
158
|
+
* recalculated.
|
|
159
|
+
*
|
|
160
|
+
* the idea is to know the bottom/right row/column of the annotation,
|
|
161
|
+
* so when we preserve/restore the sheet we don't trim those rows/columns.
|
|
162
|
+
* they don't need any data, but it just looks bad. we can do this
|
|
163
|
+
* dynamically but since it won't change all that often, we might
|
|
164
|
+
* as well precalculate.
|
|
165
|
+
*/
|
|
166
|
+
public extent?: ICellAddress;
|
|
167
|
+
|
|
168
|
+
private key_ = (key_generator++);
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* constructor takes a property bag (from json, generally). note that
|
|
172
|
+
* if you are iterating keys on `this`, there has to be an initial value
|
|
173
|
+
* or the key won't exist.
|
|
174
|
+
*/
|
|
175
|
+
constructor(opts: Partial<Annotation>&{rect?: Partial<Rectangle>} = {}) {
|
|
176
|
+
for (const key of Object.keys(this) as Array<keyof Annotation>){
|
|
177
|
+
if (key !== 'layout' // && key !== 'rect'
|
|
178
|
+
&& opts[key]) { // key !== 'cell_address' && opts[key]) {
|
|
179
|
+
(this as any)[key] = opts[key];
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (opts.layout) {
|
|
184
|
+
this.layout = JSON.parse(JSON.stringify(opts.layout));
|
|
185
|
+
}
|
|
186
|
+
if (opts.rect) {
|
|
187
|
+
this.rect = Rectangle.Create(opts.rect);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* serialization method drops node and trims
|
|
193
|
+
*/
|
|
194
|
+
public toJSON(): Partial<Annotation> {
|
|
195
|
+
const result: Partial<Annotation> = {}; // { rect: this.rect };
|
|
196
|
+
|
|
197
|
+
if (this.data) result.data = this.data;
|
|
198
|
+
if (this.formula) result.formula = this.formula;
|
|
199
|
+
if (this.type) result.type = this.type;
|
|
200
|
+
// if (this.class_name) result.class_name = this.class_name;
|
|
201
|
+
|
|
202
|
+
if (!this.resizable) result.resizable = this.resizable;
|
|
203
|
+
if (!this.movable) result.movable = this.movable;
|
|
204
|
+
if (!this.removable) result.removable = this.removable;
|
|
205
|
+
if (!this.selectable) result.selectable = this.selectable;
|
|
206
|
+
|
|
207
|
+
if (!this.move_with_cells) result.move_with_cells = this.move_with_cells;
|
|
208
|
+
if (!this.resize_with_cells) result.resize_with_cells = this.resize_with_cells;
|
|
209
|
+
|
|
210
|
+
if (this.layout) result.layout = this.layout;
|
|
211
|
+
if (this.extent) result.extent = this.extent;
|
|
212
|
+
|
|
213
|
+
return result;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of TREB.
|
|
3
|
+
*
|
|
4
|
+
* TREB is free software: you can redistribute it and/or modify it under the
|
|
5
|
+
* terms of the GNU General Public License as published by the Free Software
|
|
6
|
+
* Foundation, either version 3 of the License, or (at your option) any
|
|
7
|
+
* later version.
|
|
8
|
+
*
|
|
9
|
+
* TREB is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
10
|
+
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
11
|
+
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
12
|
+
* details.
|
|
13
|
+
*
|
|
14
|
+
* You should have received a copy of the GNU General Public License along
|
|
15
|
+
* with TREB. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
*
|
|
17
|
+
* Copyright 2022-2023 trebco, llc.
|
|
18
|
+
* info@treb.app
|
|
19
|
+
*
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
// switching to string constants to make it easier to set manually
|
|
23
|
+
|
|
24
|
+
export enum BorderConstants {
|
|
25
|
+
None = 'none',
|
|
26
|
+
All = 'all',
|
|
27
|
+
Outside = 'outside',
|
|
28
|
+
Top = 'top',
|
|
29
|
+
Bottom = 'bottom',
|
|
30
|
+
Left = 'left',
|
|
31
|
+
Right = 'right',
|
|
32
|
+
// DoubleTop = 'double-top',
|
|
33
|
+
// DoubleBottom = 'double-bottom',
|
|
34
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of TREB.
|
|
3
|
+
*
|
|
4
|
+
* TREB is free software: you can redistribute it and/or modify it under the
|
|
5
|
+
* terms of the GNU General Public License as published by the Free Software
|
|
6
|
+
* Foundation, either version 3 of the License, or (at your option) any
|
|
7
|
+
* later version.
|
|
8
|
+
*
|
|
9
|
+
* TREB is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
10
|
+
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
11
|
+
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
12
|
+
* details.
|
|
13
|
+
*
|
|
14
|
+
* You should have received a copy of the GNU General Public License along
|
|
15
|
+
* with TREB. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
*
|
|
17
|
+
* Copyright 2022-2023 trebco, llc.
|
|
18
|
+
* info@treb.app
|
|
19
|
+
*
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
import type { ICellAddress, CellValue, ValueType, Style } from 'treb-base-types';
|
|
24
|
+
|
|
25
|
+
export interface ClipboardCellData {
|
|
26
|
+
address: ICellAddress;
|
|
27
|
+
data: CellValue;
|
|
28
|
+
type: ValueType;
|
|
29
|
+
style?: Style.Properties;
|
|
30
|
+
array?: {rows: number, columns: number};
|
|
31
|
+
}
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of TREB.
|
|
3
|
+
*
|
|
4
|
+
* TREB is free software: you can redistribute it and/or modify it under the
|
|
5
|
+
* terms of the GNU General Public License as published by the Free Software
|
|
6
|
+
* Foundation, either version 3 of the License, or (at your option) any
|
|
7
|
+
* later version.
|
|
8
|
+
*
|
|
9
|
+
* TREB is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
10
|
+
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
11
|
+
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
12
|
+
* details.
|
|
13
|
+
*
|
|
14
|
+
* You should have received a copy of the GNU General Public License along
|
|
15
|
+
* with TREB. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
*
|
|
17
|
+
* Copyright 2022-2023 trebco, llc.
|
|
18
|
+
* info@treb.app
|
|
19
|
+
*
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import type { Sheet } from './sheet';
|
|
23
|
+
import type { IArea, ICellAddress, Table } from 'treb-base-types';
|
|
24
|
+
import type { SerializedSheet } from './sheet_types';
|
|
25
|
+
import { NamedRangeCollection } from './named_range';
|
|
26
|
+
import type { ExpressionUnit, UnitAddress, UnitStructuredReference, UnitRange } from 'treb-parser';
|
|
27
|
+
import { Style } from 'treb-base-types';
|
|
28
|
+
|
|
29
|
+
export interface MacroFunction {
|
|
30
|
+
name: string;
|
|
31
|
+
function_def: string;
|
|
32
|
+
argument_names?: string[];
|
|
33
|
+
// argument_default_values?: any[]; // <- new
|
|
34
|
+
description?: string;
|
|
35
|
+
expression?: ExpressionUnit;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* we spend a lot of time looking up sheets by name, or id, or
|
|
40
|
+
* sometimes index. it makes sense to have a class that can
|
|
41
|
+
* support all of these, ideally without looping.
|
|
42
|
+
*
|
|
43
|
+
* we just have to make sure that no one is assigning to the
|
|
44
|
+
* array, or we'll lose track.
|
|
45
|
+
*
|
|
46
|
+
* also there are some operations -- rename, in particular -- that
|
|
47
|
+
* require updating indexes.
|
|
48
|
+
*
|
|
49
|
+
*
|
|
50
|
+
* FIXME: new file (1 class per file)
|
|
51
|
+
*/
|
|
52
|
+
export class SheetCollection {
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* returns a read-only copy of the list. useful for indexing or
|
|
56
|
+
* functional-style calls. it's not actually read-only, but it's a
|
|
57
|
+
* copy, so changes will be ignored.
|
|
58
|
+
*/
|
|
59
|
+
public get list() {
|
|
60
|
+
return this.sheets_.slice(0);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* length of list
|
|
65
|
+
*/
|
|
66
|
+
public get length() {
|
|
67
|
+
return this.sheets_.length;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** map of (normalized) name -> sheet */
|
|
71
|
+
protected names: Map<string, Sheet> = new Map();
|
|
72
|
+
|
|
73
|
+
/** map of id -> sheet */
|
|
74
|
+
protected ids: Map<number, Sheet> = new Map();
|
|
75
|
+
|
|
76
|
+
/** the actual list */
|
|
77
|
+
private sheets_: Sheet[] = [];
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* remove any existing sheets and add the passed list. updates indexes.
|
|
81
|
+
*/
|
|
82
|
+
public Assign(sheets: Sheet[]) {
|
|
83
|
+
this.sheets_ = [...sheets];
|
|
84
|
+
this.UpdateIndexes();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* add a new sheet to the end of the list (push). updates indexes.
|
|
89
|
+
*/
|
|
90
|
+
public Add(sheet: Sheet) {
|
|
91
|
+
this.sheets_.push(sheet);
|
|
92
|
+
this.UpdateIndexes();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* wrapper for array splice. updates indexes.
|
|
97
|
+
*/
|
|
98
|
+
public Splice(insert_index: number, delete_count: number, ...items: Sheet[]) {
|
|
99
|
+
this.sheets_.splice(insert_index, delete_count, ...items);
|
|
100
|
+
this.UpdateIndexes();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* so our new strategy is to add lookup methods first -- then
|
|
105
|
+
* we can fix the underlying storage implementation.
|
|
106
|
+
*
|
|
107
|
+
* NOTE we normalize strings here so you do not need to do it (don't)
|
|
108
|
+
*/
|
|
109
|
+
public Find(id: string|number): Sheet|undefined {
|
|
110
|
+
|
|
111
|
+
// console.info('get', typeof id);
|
|
112
|
+
|
|
113
|
+
if (typeof id === 'string') {
|
|
114
|
+
return this.names.get(id.toLocaleUpperCase());
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
return this.ids.get(id);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** get name for sheet with given id */
|
|
124
|
+
public Name(id: number): string|undefined {
|
|
125
|
+
return this.ids.get(id)?.name || undefined;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** get ID for sheet with given name */
|
|
129
|
+
public ID(name: string): number|undefined {
|
|
130
|
+
return this.names.get(name.toLocaleUpperCase())?.id || undefined;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** not sure why this is private, makes it a little more complicated */
|
|
134
|
+
public UpdateIndexes(): void {
|
|
135
|
+
|
|
136
|
+
this.names.clear();
|
|
137
|
+
this.ids.clear();
|
|
138
|
+
|
|
139
|
+
for (const sheet of this.sheets_) {
|
|
140
|
+
const uc = sheet.name.toLocaleUpperCase();
|
|
141
|
+
this.names.set(uc, sheet);
|
|
142
|
+
this.ids.set(sheet.id, sheet);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* FIXME: this should move out of the grid module, grid should be focused on view
|
|
152
|
+
*/
|
|
153
|
+
export class DataModel {
|
|
154
|
+
|
|
155
|
+
/** document metadata */
|
|
156
|
+
public document_name?: string;
|
|
157
|
+
|
|
158
|
+
/** document metadata */
|
|
159
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
160
|
+
public user_data?: any;
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* list of sheets. we _should_ index these by ID, so we
|
|
164
|
+
* don't have to look up. FIXME/TODO
|
|
165
|
+
*/
|
|
166
|
+
// public sheets: Sheet[] = [];
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* this prevents assignment, but not push/pop/splice (baby steps)
|
|
170
|
+
*/
|
|
171
|
+
// public get sheets(): Sheet[] {
|
|
172
|
+
// return this._sheets;
|
|
173
|
+
//}
|
|
174
|
+
public readonly sheets = new SheetCollection();
|
|
175
|
+
|
|
176
|
+
/** named ranges are document-scope, we don't support sheet-scope names */
|
|
177
|
+
public readonly named_ranges = new NamedRangeCollection;
|
|
178
|
+
|
|
179
|
+
/** macro functions are functions written in spreadsheet language */
|
|
180
|
+
// public macro_functions: Record<string, MacroFunction> = {};
|
|
181
|
+
public readonly macro_functions: Map<string, MacroFunction> = new Map();
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* new, for parametric. these might move to a different construct.
|
|
185
|
+
*/
|
|
186
|
+
//public named_expressions: Record<string, ExpressionUnit> = {};
|
|
187
|
+
public readonly named_expressions: Map<string, ExpressionUnit> = new Map();
|
|
188
|
+
|
|
189
|
+
/** index for views */
|
|
190
|
+
public view_count = 0;
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* base style properties moved to model, so we can have a single
|
|
194
|
+
* and consistent reference.
|
|
195
|
+
*/
|
|
196
|
+
public theme_style_properties: Style.Properties = JSON.parse(JSON.stringify(Style.DefaultProperties));
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* tables are global, because we need to reference them by name; and they
|
|
200
|
+
* need unique names, so we need to keep track of names. name matching is
|
|
201
|
+
* icase so we lc the names before inserting.
|
|
202
|
+
*/
|
|
203
|
+
public tables: Map<string, Table> = new Map();
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* putting this here temporarily. it should probably move into a table
|
|
207
|
+
* manager class or something like that.
|
|
208
|
+
*/
|
|
209
|
+
public ResolveStructuredReference(ref: UnitStructuredReference, context: ICellAddress): UnitAddress|UnitRange|undefined {
|
|
210
|
+
|
|
211
|
+
let table: Table|undefined;
|
|
212
|
+
|
|
213
|
+
// if there's no table specified, it means "I am in the table".
|
|
214
|
+
// in that case we need to find the table from the cell.
|
|
215
|
+
|
|
216
|
+
if (ref.table) {
|
|
217
|
+
table = this.tables.get(ref.table.toLowerCase());
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
if (context.sheet_id) {
|
|
221
|
+
const sheet = this.sheets.Find(context.sheet_id);
|
|
222
|
+
const cell = sheet?.CellData(context);
|
|
223
|
+
table = cell?.table;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (!table) {
|
|
228
|
+
return undefined; // table not found
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// resolve the column
|
|
232
|
+
const reference_column = ref.column.toLowerCase();
|
|
233
|
+
let column = -1;
|
|
234
|
+
|
|
235
|
+
if (table.columns) { // FIXME: make this required
|
|
236
|
+
for (let i = 0; i < table.columns.length; i++) {
|
|
237
|
+
if (reference_column === table.columns[i]) {
|
|
238
|
+
column = table.area.start.column + i;
|
|
239
|
+
break;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (column < 0) {
|
|
245
|
+
return undefined; // invalid column
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// for row scope, make sure we're in a valid row.
|
|
249
|
+
|
|
250
|
+
if (ref.scope === 'row') {
|
|
251
|
+
|
|
252
|
+
const row = context.row;
|
|
253
|
+
if (row < table.area.start.row || row > table.area.end.row) {
|
|
254
|
+
return undefined; // invalid row for "this row"
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// OK, we can use this
|
|
258
|
+
|
|
259
|
+
return {
|
|
260
|
+
label: ref.label,
|
|
261
|
+
type: 'address',
|
|
262
|
+
row,
|
|
263
|
+
column,
|
|
264
|
+
sheet_id: table.area.start.sheet_id,
|
|
265
|
+
id: ref.id,
|
|
266
|
+
position: ref.position,
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
|
|
272
|
+
// the difference between 'all' and 'column' is that 'all' includes
|
|
273
|
+
// the first (header) row and the last (totals) row, if we have one.
|
|
274
|
+
|
|
275
|
+
let start_row = table.area.start.row;
|
|
276
|
+
let end_row = table.area.end.row;
|
|
277
|
+
|
|
278
|
+
if (ref.scope === 'column') {
|
|
279
|
+
start_row++; // skip headers
|
|
280
|
+
if (table.totals_row) {
|
|
281
|
+
end_row--; // skip totals
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return {
|
|
286
|
+
label: ref.label,
|
|
287
|
+
type: 'range',
|
|
288
|
+
position: ref.position,
|
|
289
|
+
id: ref.id,
|
|
290
|
+
start: {
|
|
291
|
+
type: 'address',
|
|
292
|
+
row: start_row,
|
|
293
|
+
column,
|
|
294
|
+
sheet_id: table.area.start.sheet_id,
|
|
295
|
+
label: ref.label,
|
|
296
|
+
position: ref.position,
|
|
297
|
+
id: 0,
|
|
298
|
+
},
|
|
299
|
+
end: {
|
|
300
|
+
type: 'address',
|
|
301
|
+
row: end_row,
|
|
302
|
+
column,
|
|
303
|
+
label: ref.label,
|
|
304
|
+
position: ref.position,
|
|
305
|
+
id: 0,
|
|
306
|
+
},
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
return undefined;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
export interface ViewModel {
|
|
317
|
+
active_sheet: Sheet;
|
|
318
|
+
view_index: number;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
export interface SerializedNamedExpression {
|
|
322
|
+
name: string;
|
|
323
|
+
expression: string;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
export interface SerializedModel {
|
|
327
|
+
sheet_data: SerializedSheet[];
|
|
328
|
+
active_sheet: number;
|
|
329
|
+
named_ranges?: Record<string, IArea>;
|
|
330
|
+
macro_functions?: MacroFunction[];
|
|
331
|
+
tables?: Table[];
|
|
332
|
+
named_expressions?: SerializedNamedExpression[];
|
|
333
|
+
decimal_mark?: ','|'.';
|
|
334
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of TREB.
|
|
3
|
+
*
|
|
4
|
+
* TREB is free software: you can redistribute it and/or modify it under the
|
|
5
|
+
* terms of the GNU General Public License as published by the Free Software
|
|
6
|
+
* Foundation, either version 3 of the License, or (at your option) any
|
|
7
|
+
* later version.
|
|
8
|
+
*
|
|
9
|
+
* TREB is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
10
|
+
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
11
|
+
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
12
|
+
* details.
|
|
13
|
+
*
|
|
14
|
+
* You should have received a copy of the GNU General Public License along
|
|
15
|
+
* with TREB. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
*
|
|
17
|
+
* Copyright 2022-2023 trebco, llc.
|
|
18
|
+
* info@treb.app
|
|
19
|
+
*
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* generic method for mouse drag handling. this method will insert an
|
|
24
|
+
* event mask to capture mouse events over the whole window, and call
|
|
25
|
+
* optional functions on events.
|
|
26
|
+
*
|
|
27
|
+
* @param classes optional list of classes to attach to the mask node
|
|
28
|
+
* @param move callback function on mouse move events
|
|
29
|
+
* @param end callback function on end (mouse up or button up)
|
|
30
|
+
*/
|
|
31
|
+
export function MouseDrag(
|
|
32
|
+
mask_node: HTMLElement,
|
|
33
|
+
classes: string|string[] = [],
|
|
34
|
+
move?: (event: MouseEvent) => void,
|
|
35
|
+
end?: (event: MouseEvent) => void) {
|
|
36
|
+
|
|
37
|
+
if (typeof classes === 'string') {
|
|
38
|
+
classes = [classes];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// eslint-disable-next-line prefer-const
|
|
42
|
+
let cleanup: () => void;
|
|
43
|
+
|
|
44
|
+
const handle_up = (event: MouseEvent) => {
|
|
45
|
+
event.stopPropagation();
|
|
46
|
+
event.preventDefault();
|
|
47
|
+
cleanup();
|
|
48
|
+
// if (end) end.call(this, event);
|
|
49
|
+
if (end) { end(event); }
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const handle_move = (event: MouseEvent) => {
|
|
53
|
+
event.stopPropagation();
|
|
54
|
+
event.preventDefault();
|
|
55
|
+
if (!event.buttons) {
|
|
56
|
+
cleanup();
|
|
57
|
+
// if (end) end.call(this, event);
|
|
58
|
+
if (end) { end(event); }
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
// if (move) move.call(this, event);
|
|
62
|
+
if (move) { move(event); }
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
cleanup = () => {
|
|
66
|
+
mask_node.style.display = 'none';
|
|
67
|
+
mask_node.removeEventListener('mousemove', handle_move);
|
|
68
|
+
mask_node.removeEventListener('mouseup', handle_up);
|
|
69
|
+
for (const class_entry of classes) mask_node.classList.remove(class_entry);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
for (const class_entry of classes) mask_node.classList.add(class_entry);
|
|
73
|
+
mask_node.style.display = 'block';
|
|
74
|
+
|
|
75
|
+
// listeners are only added if we're going to use the callbacks.
|
|
76
|
+
// still safe to call remove listener even if they're not added.
|
|
77
|
+
|
|
78
|
+
if (move) mask_node.addEventListener('mousemove', handle_move);
|
|
79
|
+
if (end) mask_node.addEventListener('mouseup', handle_up);
|
|
80
|
+
|
|
81
|
+
}
|