@trebco/treb 23.6.5 → 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} +285 -269
- 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,36 @@
|
|
|
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 { ICellAddress, IArea } from './area';
|
|
23
|
+
|
|
24
|
+
// for updated API functions
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* type represents a reference passed in to API functions. it can be an
|
|
28
|
+
* address object, or a string.
|
|
29
|
+
*/
|
|
30
|
+
export type AddressReference = string | ICellAddress;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* type represents a reference passed in to API functions. it can be an
|
|
34
|
+
* address object, an area (range) object, or a string.
|
|
35
|
+
*/
|
|
36
|
+
export type RangeReference = string | ICellAddress | IArea;
|
|
@@ -0,0 +1,583 @@
|
|
|
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
|
+
* Structure represents a cell address. Note that row and column are 0-based.
|
|
24
|
+
*/
|
|
25
|
+
export interface ICellAddress {
|
|
26
|
+
|
|
27
|
+
/** 0-based row */
|
|
28
|
+
row: number;
|
|
29
|
+
|
|
30
|
+
/** 0-based column */
|
|
31
|
+
column: number;
|
|
32
|
+
|
|
33
|
+
absolute_row?: boolean;
|
|
34
|
+
absolute_column?: boolean;
|
|
35
|
+
sheet_id?: number;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* this version of the interface requires a sheet ID
|
|
40
|
+
*/
|
|
41
|
+
export interface ICellAddress2 extends ICellAddress {
|
|
42
|
+
sheet_id: number;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Structure represents a 2d range of cells.
|
|
47
|
+
*
|
|
48
|
+
* @privateRemarks
|
|
49
|
+
*
|
|
50
|
+
* FIXME: should be just Partial<Area>? (...) OTOH, this at least
|
|
51
|
+
* enforces two addresses, which seems useful
|
|
52
|
+
*/
|
|
53
|
+
export interface IArea {
|
|
54
|
+
start: ICellAddress;
|
|
55
|
+
end: ICellAddress;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* type guard function
|
|
60
|
+
* FIXME: is there a naming convention for these?
|
|
61
|
+
*
|
|
62
|
+
* @internal
|
|
63
|
+
*/
|
|
64
|
+
export const IsCellAddress = (obj: any): obj is ICellAddress => {
|
|
65
|
+
return (
|
|
66
|
+
typeof obj === 'object' &&
|
|
67
|
+
typeof obj.row !== 'undefined' &&
|
|
68
|
+
typeof obj.column !== 'undefined');
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
/** @internal */
|
|
72
|
+
export const IsArea = (obj: any): obj is IArea => {
|
|
73
|
+
return (
|
|
74
|
+
typeof obj === 'object' &&
|
|
75
|
+
IsCellAddress(obj.start) &&
|
|
76
|
+
IsCellAddress(obj.end));
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export interface Dimensions {
|
|
80
|
+
rows: number;
|
|
81
|
+
columns: number;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* class represents a rectangular area on a sheet. can be a range,
|
|
86
|
+
* single cell, entire row/column, or entire sheet.
|
|
87
|
+
*
|
|
88
|
+
* "entire" row/column/sheet is represented with an infinity in the
|
|
89
|
+
* start/end value for row/column/both, so watch out on loops. the
|
|
90
|
+
* sheet class has a method for reducing infinite ranges to actual
|
|
91
|
+
* populated ranges.
|
|
92
|
+
*/
|
|
93
|
+
export class Area implements IArea { // }, IterableIterator<ICellAddress> {
|
|
94
|
+
|
|
95
|
+
// tslint:disable-next-line:variable-name
|
|
96
|
+
private start_: ICellAddress;
|
|
97
|
+
|
|
98
|
+
// tslint:disable-next-line:variable-name
|
|
99
|
+
private end_: ICellAddress;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
*
|
|
103
|
+
* @param start
|
|
104
|
+
* @param end
|
|
105
|
+
* @param normalize: calls the normalize function
|
|
106
|
+
*/
|
|
107
|
+
constructor(start: ICellAddress, end: ICellAddress = start, normalize = false){
|
|
108
|
+
|
|
109
|
+
/*
|
|
110
|
+
// copy
|
|
111
|
+
this.start_ = {
|
|
112
|
+
row: start.row, column: start.column,
|
|
113
|
+
absolute_column: !!start.absolute_column,
|
|
114
|
+
absolute_row: !!start.absolute_row };
|
|
115
|
+
|
|
116
|
+
this.end_ = {
|
|
117
|
+
row: end.row, column: end.column,
|
|
118
|
+
absolute_column: !!end.absolute_column,
|
|
119
|
+
absolute_row: !!end.absolute_row };
|
|
120
|
+
*/
|
|
121
|
+
|
|
122
|
+
// patch nulls. this is an effect of transferring via JSON,
|
|
123
|
+
// infinities are -> null. make sure to strict === null.
|
|
124
|
+
|
|
125
|
+
// NOTE that the patch function returns a clone, so we can store the
|
|
126
|
+
// returned object (instead of copying, which we used to do).
|
|
127
|
+
|
|
128
|
+
this.end_ = this.PatchNull(end);
|
|
129
|
+
this.start_ = this.PatchNull(start);
|
|
130
|
+
|
|
131
|
+
if (normalize) this.Normalize();
|
|
132
|
+
|
|
133
|
+
// this.ResetIterator();
|
|
134
|
+
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
public static FromColumn(column: number): Area {
|
|
138
|
+
return new Area({row: Infinity, column});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
public static FromRow(row: number): Area {
|
|
142
|
+
return new Area({row, column: Infinity});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
public static ColumnToLabel(c: number): string {
|
|
146
|
+
let s = String.fromCharCode(65 + c % 26);
|
|
147
|
+
while (c > 25){
|
|
148
|
+
c = Math.floor(c / 26) - 1;
|
|
149
|
+
s = String.fromCharCode(65 + c % 26) + s;
|
|
150
|
+
}
|
|
151
|
+
return s;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
public static CellAddressToLabel(address: ICellAddress, sheet_id = false): string {
|
|
155
|
+
|
|
156
|
+
const prefix = sheet_id ? `${address.sheet_id || 0}!` : '';
|
|
157
|
+
|
|
158
|
+
return prefix
|
|
159
|
+
+ (address.absolute_column ? '$' : '')
|
|
160
|
+
+ this.ColumnToLabel(address.column)
|
|
161
|
+
+ (address.absolute_row ? '$' : '')
|
|
162
|
+
+ (address.row + 1);
|
|
163
|
+
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* merge two areas and return a new area.
|
|
168
|
+
* UPDATE to support arbitrary arguments
|
|
169
|
+
*/
|
|
170
|
+
public static Join(base: IArea, ...args: Array<IArea|undefined>): Area {
|
|
171
|
+
const area = new Area(base.start, base.end);
|
|
172
|
+
for (const arg of args) {
|
|
173
|
+
if (arg) {
|
|
174
|
+
area.ConsumeAddress(arg.start);
|
|
175
|
+
area.ConsumeAddress(arg.end);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return area;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* creates an area that expands the original area in all directions
|
|
183
|
+
* (except at the top/left edges)
|
|
184
|
+
*/
|
|
185
|
+
public static Bleed(area: IArea, length = 1): Area {
|
|
186
|
+
return new Area({
|
|
187
|
+
row: Math.max(0, area.start.row - length),
|
|
188
|
+
column: Math.max(0, area.start.column - length),
|
|
189
|
+
sheet_id: area.start.sheet_id,
|
|
190
|
+
}, {
|
|
191
|
+
row: area.end.row + length,
|
|
192
|
+
column: area.end.column + length,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
/** accessor returns a _copy_ of the start address */
|
|
199
|
+
public get start(): ICellAddress {
|
|
200
|
+
return { ...this.start_ };
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** accessor */
|
|
204
|
+
public set start(value: ICellAddress){ this.start_ = value; }
|
|
205
|
+
|
|
206
|
+
/** accessor returns a _copy_ of the end address */
|
|
207
|
+
public get end(): ICellAddress {
|
|
208
|
+
return { ...this.end_ };
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** accessor */
|
|
212
|
+
public set end(value: ICellAddress){ this.end_ = value; }
|
|
213
|
+
|
|
214
|
+
/** returns number of rows, possibly infinity */
|
|
215
|
+
public get rows(): number {
|
|
216
|
+
if (this.start_.row === Infinity || this.end_.row === Infinity) return Infinity;
|
|
217
|
+
return this.end_.row - this.start_.row + 1;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/** returns number of columns, possibly infinity */
|
|
221
|
+
public get columns(): number {
|
|
222
|
+
if (this.start_.column === Infinity || this.end_.column === Infinity) return Infinity;
|
|
223
|
+
return this.end_.column - this.start_.column + 1;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/** returns number of cells, possibly infinity */
|
|
227
|
+
public get count(): number {
|
|
228
|
+
return this.rows * this.columns;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/** returns flag indicating this is the entire sheet, usually after "select all" */
|
|
232
|
+
public get entire_sheet(): boolean {
|
|
233
|
+
return this.entire_row && this.entire_column;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/** returns flag indicating this range includes infinite rows */
|
|
237
|
+
public get entire_column(): boolean {
|
|
238
|
+
return (this.start_.row === Infinity);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/** returns flag indicating this range includes infinite columns */
|
|
242
|
+
public get entire_row(): boolean {
|
|
243
|
+
return (this.start_.column === Infinity);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
public PatchNull(address: ICellAddress): ICellAddress {
|
|
247
|
+
const copy = { ...address };
|
|
248
|
+
if (copy.row === null) { copy.row = Infinity; }
|
|
249
|
+
if (copy.column === null) { copy.column = Infinity; }
|
|
250
|
+
return copy;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
public SetSheetID(id: number) {
|
|
254
|
+
this.start_.sheet_id = id;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
public Normalize(){
|
|
258
|
+
/*
|
|
259
|
+
let columns = [this.start.column, this.end.column].sort((a, b) => a-b);
|
|
260
|
+
let rows = [this.start.row, this.end.row].sort((a, b) => a-b);
|
|
261
|
+
|
|
262
|
+
this.start_ = {row: rows[0], column: columns[0]};
|
|
263
|
+
this.end = {row:rows[1], column: columns[1]};
|
|
264
|
+
*/
|
|
265
|
+
|
|
266
|
+
// we need to bind the element and the absolute/relative status
|
|
267
|
+
// so sorting is too simple
|
|
268
|
+
|
|
269
|
+
const start = { ...this.start_ };
|
|
270
|
+
const end = { ...this.end_ };
|
|
271
|
+
|
|
272
|
+
/*
|
|
273
|
+
const start = {
|
|
274
|
+
sheet_id: this.start_.sheet_id,
|
|
275
|
+
row: this.start_.row,
|
|
276
|
+
column: this.start_.column,
|
|
277
|
+
absolute_column: this.start_.absolute_column,
|
|
278
|
+
absolute_row: this.start_.absolute_row };
|
|
279
|
+
|
|
280
|
+
const end = {
|
|
281
|
+
sheet_id: this.end_.sheet_id, // we don't ever use this, but copy JIC
|
|
282
|
+
row: this.end_.row,
|
|
283
|
+
column: this.end_.column,
|
|
284
|
+
absolute_column: this.end_.absolute_column,
|
|
285
|
+
absolute_row: this.end_.absolute_row };
|
|
286
|
+
*/
|
|
287
|
+
|
|
288
|
+
// swap row
|
|
289
|
+
|
|
290
|
+
if (start.row === Infinity || end.row === Infinity){
|
|
291
|
+
start.row = end.row = Infinity;
|
|
292
|
+
}
|
|
293
|
+
else if (start.row > end.row){
|
|
294
|
+
start.row = this.end_.row;
|
|
295
|
+
start.absolute_row = this.end_.absolute_row;
|
|
296
|
+
end.row = this.start_.row;
|
|
297
|
+
end.absolute_row = this.start_.absolute_row;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// swap column
|
|
301
|
+
|
|
302
|
+
if (start.column === Infinity || end.column === Infinity){
|
|
303
|
+
start.column = end.column = Infinity;
|
|
304
|
+
}
|
|
305
|
+
else if (start.column > end.column){
|
|
306
|
+
start.column = this.end_.column;
|
|
307
|
+
start.absolute_column = this.end_.absolute_column;
|
|
308
|
+
end.column = this.start_.column;
|
|
309
|
+
end.absolute_column = this.start_.absolute_column;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
this.start_ = start;
|
|
313
|
+
this.end_ = end;
|
|
314
|
+
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/** returns the top-left cell in the area */
|
|
318
|
+
public TopLeft(): ICellAddress {
|
|
319
|
+
const address = {row: 0, column: 0};
|
|
320
|
+
if (!this.entire_row) address.column = this.start.column;
|
|
321
|
+
if (!this.entire_column) address.row = this.start.row;
|
|
322
|
+
return address;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/** returns the bottom-right cell in the area */
|
|
326
|
+
public BottomRight(): ICellAddress {
|
|
327
|
+
const address = {row: 0, column: 0};
|
|
328
|
+
if (!this.entire_row) address.column = this.end.column;
|
|
329
|
+
if (!this.entire_column) address.row = this.end.row;
|
|
330
|
+
return address;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
public ContainsRow(row: number): boolean {
|
|
334
|
+
return this.entire_column || (row >= this.start_.row && row <= this.end_.row);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
public ContainsColumn(column: number): boolean {
|
|
338
|
+
return this.entire_row || (column >= this.start_.column && column <= this.end_.column);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
public Contains(address: ICellAddress): boolean {
|
|
342
|
+
return (this.entire_column || (address.row >= this.start_.row && address.row <= this.end_.row))
|
|
343
|
+
&& (this.entire_row || (address.column >= this.start_.column && address.column <= this.end_.column));
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* returns true if this area completely contains the argument area
|
|
348
|
+
* (also if areas are ===, as a side effect). note that this returns
|
|
349
|
+
* true if A contains B, but not vice-versa
|
|
350
|
+
*/
|
|
351
|
+
public ContainsArea(area: Area): boolean {
|
|
352
|
+
return this.start.column <= area.start.column
|
|
353
|
+
&& this.end.column >= area.end.column
|
|
354
|
+
&& this.start.row <= area.start.row
|
|
355
|
+
&& this.end.row >= area.end.row;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* returns true if there's an intersection. note that this won't work
|
|
360
|
+
* if there are infinities -- needs real area ?
|
|
361
|
+
*/
|
|
362
|
+
public Intersects(area: Area): boolean {
|
|
363
|
+
return !(area.start.column > this.end.column
|
|
364
|
+
|| this.start.column > area.end.column
|
|
365
|
+
|| area.start.row > this.end.row
|
|
366
|
+
|| this.start.row > area.end.row);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
public Equals(area: Area): boolean {
|
|
370
|
+
return area.start_.row === this.start_.row
|
|
371
|
+
&& area.start_.column === this.start_.column
|
|
372
|
+
&& area.end_.row === this.end_.row
|
|
373
|
+
&& area.end_.column === this.end_.column;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
public Clone(): Area {
|
|
377
|
+
return new Area(this.start, this.end); // ensure copies
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
public Array(): ICellAddress[] {
|
|
381
|
+
if (this.entire_column || this.entire_row) throw new Error('can\'t convert infinite area to array');
|
|
382
|
+
const array: ICellAddress[] = new Array<ICellAddress>(this.rows * this.columns);
|
|
383
|
+
|
|
384
|
+
const sheet_id = this.start_.sheet_id;
|
|
385
|
+
let index = 0;
|
|
386
|
+
|
|
387
|
+
// does this need sheet ID?
|
|
388
|
+
|
|
389
|
+
for (let row = this.start_.row; row <= this.end_.row; row++){
|
|
390
|
+
for (let column = this.start_.column; column <= this.end_.column; column++){
|
|
391
|
+
array[index++] = { row, column, sheet_id };
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
return array;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
get left(): Area{
|
|
398
|
+
const area = new Area(this.start_, this.end_);
|
|
399
|
+
area.end_.column = area.start_.column;
|
|
400
|
+
return area;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
get right(): Area{
|
|
404
|
+
const area = new Area(this.start_, this.end_);
|
|
405
|
+
area.start_.column = area.end_.column;
|
|
406
|
+
return area;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
get top(): Area{
|
|
410
|
+
const area = new Area(this.start_, this.end_);
|
|
411
|
+
area.end_.row = area.start_.row;
|
|
412
|
+
return area;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
get bottom(): Area{
|
|
416
|
+
const area = new Area(this.start_, this.end_);
|
|
417
|
+
area.start_.row = area.end_.row;
|
|
418
|
+
return area;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/** shifts range in place */
|
|
422
|
+
public Shift(rows: number, columns: number): Area {
|
|
423
|
+
this.start_.row += rows;
|
|
424
|
+
this.start_.column += columns;
|
|
425
|
+
this.end_.row += rows;
|
|
426
|
+
this.end_.column += columns;
|
|
427
|
+
return this; // fluent
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/** Resizes range in place so that it includes the given address */
|
|
431
|
+
public ConsumeAddress(addr: ICellAddress): void {
|
|
432
|
+
if (!this.entire_row){
|
|
433
|
+
if (addr.column < this.start_.column) this.start_.column = addr.column;
|
|
434
|
+
if (addr.column > this.end_.column) this.end_.column = addr.column;
|
|
435
|
+
}
|
|
436
|
+
if (!this.entire_column){
|
|
437
|
+
if (addr.row < this.start_.row) this.start_.row = addr.row;
|
|
438
|
+
if (addr.row > this.end_.row) this.end_.row = addr.row;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/** Resizes range in place so that it includes the given area (merge) */
|
|
443
|
+
public ConsumeArea(area: IArea): void {
|
|
444
|
+
this.ConsumeAddress(area.start);
|
|
445
|
+
this.ConsumeAddress(area.end);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/** resizes range in place (updates end) */
|
|
449
|
+
public Resize(rows: number, columns: number): Area {
|
|
450
|
+
this.end_.row = this.start_.row + rows - 1;
|
|
451
|
+
this.end_.column = this.start_.column + columns - 1;
|
|
452
|
+
return this; // fluent
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
public Iterate(f: (...args: any[]) => any): void {
|
|
456
|
+
if (this.entire_column || this.entire_row) {
|
|
457
|
+
console.warn(`don't iterate infinite area`);
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
for (let c = this.start_.column; c <= this.end_.column; c++){
|
|
461
|
+
for (let r = this.start_.row; r <= this.end_.row; r++){
|
|
462
|
+
f({column: c, row: r, sheet_id: this.start_.sheet_id});
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/* *
|
|
468
|
+
* testing: we may have to polyfill for IE11, or just not use it at
|
|
469
|
+
* all, depending on support level... but it works OK (kind of a clumsy
|
|
470
|
+
* implementation though).
|
|
471
|
+
*
|
|
472
|
+
* as it turns out we don't really use iteration that much (I thought
|
|
473
|
+
* we did) so it's probably not worth the polyfill...
|
|
474
|
+
*
|
|
475
|
+
* /
|
|
476
|
+
public next(): IteratorResult<ICellAddress> {
|
|
477
|
+
|
|
478
|
+
// sanity
|
|
479
|
+
|
|
480
|
+
if (this.entire_column || this.entire_row) {
|
|
481
|
+
console.warn('don\'t iterate over infinte range');
|
|
482
|
+
return { value: undefined, done: true };
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// return current, unless it's OOB; if so, advance
|
|
486
|
+
|
|
487
|
+
if (this.iterator_index.column > this.end.column) {
|
|
488
|
+
this.iterator_index.column = this.start_.column;
|
|
489
|
+
this.iterator_index.row++;
|
|
490
|
+
|
|
491
|
+
if (this.iterator_index.row > this.end.row) {
|
|
492
|
+
this.ResetIterator();
|
|
493
|
+
return { value: undefined, done: true };
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
const result = { value: { ...this.iterator_index }, done: false };
|
|
499
|
+
this.iterator_index.column++;
|
|
500
|
+
|
|
501
|
+
return result;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
public [Symbol.iterator](): IterableIterator <ICellAddress> {
|
|
505
|
+
return this;
|
|
506
|
+
}
|
|
507
|
+
*/
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* returns the range in A1-style spreadsheet addressing. if the
|
|
511
|
+
* entire sheet is selected, returns nothing (there's no way to
|
|
512
|
+
* express that in A1 notation). returns the row numbers for entire
|
|
513
|
+
* columns and vice-versa for rows.
|
|
514
|
+
*/
|
|
515
|
+
get spreadsheet_label(): string {
|
|
516
|
+
|
|
517
|
+
let s: string;
|
|
518
|
+
|
|
519
|
+
if (this.entire_sheet) return '';
|
|
520
|
+
|
|
521
|
+
if (this.entire_column){
|
|
522
|
+
s = Area.ColumnToLabel(this.start_.column);
|
|
523
|
+
s += ':' + Area.ColumnToLabel(this.end_.column);
|
|
524
|
+
return s;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
if (this.entire_row){
|
|
528
|
+
s = String(this.start_.row + 1);
|
|
529
|
+
s += ':' + (this.end_.row + 1);
|
|
530
|
+
return s;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
s = Area.CellAddressToLabel(this.start_);
|
|
534
|
+
if (this.columns > 1 || this.rows > 1) return s + ':' + Area.CellAddressToLabel(this.end_);
|
|
535
|
+
return s;
|
|
536
|
+
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* FIXME: is this different than what would be returned if
|
|
541
|
+
* we just used the default json serializer? (...)
|
|
542
|
+
*
|
|
543
|
+
* NOTE: we could return just the start if size === 1. if
|
|
544
|
+
* you pass an undefined to the Area class ctor it will reuse
|
|
545
|
+
* the start.
|
|
546
|
+
*
|
|
547
|
+
*/
|
|
548
|
+
public toJSON(): any {
|
|
549
|
+
|
|
550
|
+
return {
|
|
551
|
+
start: { ...this.start_ },
|
|
552
|
+
end: { ...this.end_ },
|
|
553
|
+
};
|
|
554
|
+
|
|
555
|
+
/*
|
|
556
|
+
return {
|
|
557
|
+
start: {
|
|
558
|
+
row: this.start.row,
|
|
559
|
+
absolute_row: this.start.absolute_row,
|
|
560
|
+
column: this.start.column,
|
|
561
|
+
absolute_column: this.start.absolute_column,
|
|
562
|
+
},
|
|
563
|
+
end: {
|
|
564
|
+
row: this.end.row,
|
|
565
|
+
absolute_row: this.end.absolute_row,
|
|
566
|
+
column: this.end.column,
|
|
567
|
+
absolute_column: this.end.absolute_column,
|
|
568
|
+
},
|
|
569
|
+
};
|
|
570
|
+
*/
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
/*
|
|
574
|
+
private ResetIterator() {
|
|
575
|
+
this.iterator_index = {
|
|
576
|
+
row: this.start_.row,
|
|
577
|
+
column: this.start_.column,
|
|
578
|
+
sheet_id: this.start_.sheet_id,
|
|
579
|
+
};
|
|
580
|
+
}
|
|
581
|
+
*/
|
|
582
|
+
|
|
583
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
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
|
+
* utility types collected from various other files,
|
|
24
|
+
* attempting to consolidate
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
export interface Size {
|
|
28
|
+
width: number;
|
|
29
|
+
height: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface Point {
|
|
33
|
+
x: number;
|
|
34
|
+
y: number;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface Position {
|
|
38
|
+
row: number;
|
|
39
|
+
column: number;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface Extent {
|
|
43
|
+
rows: number;
|
|
44
|
+
columns: number;
|
|
45
|
+
}
|