@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,95 @@
|
|
|
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 { IArea, SerializedCellData, Style } from 'treb-base-types';
|
|
23
|
+
import type { Annotation } from './annotation';
|
|
24
|
+
import type { GridSelection } from './grid_selection';
|
|
25
|
+
|
|
26
|
+
export interface UpdateHints {
|
|
27
|
+
data?: boolean;
|
|
28
|
+
layout?: boolean;
|
|
29
|
+
style?: boolean;
|
|
30
|
+
annotations?: boolean;
|
|
31
|
+
freeze?: boolean;
|
|
32
|
+
names?: boolean;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface FreezePane {
|
|
36
|
+
rows: number;
|
|
37
|
+
columns: number;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface ScrollOffset {
|
|
41
|
+
x: number;
|
|
42
|
+
y: number;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface SerializedSheet {
|
|
46
|
+
|
|
47
|
+
// version: string;
|
|
48
|
+
// data: any; // FIXME
|
|
49
|
+
data: SerializedCellData;
|
|
50
|
+
|
|
51
|
+
sheet_style: Style.Properties;
|
|
52
|
+
rows: number;
|
|
53
|
+
columns: number;
|
|
54
|
+
cell_styles: Array<{row: number; column: number; ref: number, rows?: number}>;
|
|
55
|
+
|
|
56
|
+
/** @deprecated */
|
|
57
|
+
cell_style_refs?: Style.Properties[]; // old
|
|
58
|
+
styles?: Style.Properties[]; // new
|
|
59
|
+
|
|
60
|
+
// row_style: Style.Properties[];
|
|
61
|
+
// column_style: Style.Properties[];
|
|
62
|
+
// row_style: Array<Style.Properties|number>;
|
|
63
|
+
// column_style: Array<Style.Properties|number>;
|
|
64
|
+
row_style: Record<number, Style.Properties|number>;
|
|
65
|
+
column_style: Record<number, Style.Properties|number>;
|
|
66
|
+
|
|
67
|
+
row_pattern?: Style.Properties[];
|
|
68
|
+
|
|
69
|
+
default_row_height?: number;
|
|
70
|
+
default_column_width?: number;
|
|
71
|
+
|
|
72
|
+
row_height?: {[index: number]: number};
|
|
73
|
+
column_width?: {[index: number]: number};
|
|
74
|
+
named_ranges?: {[index: string]: IArea};
|
|
75
|
+
freeze?: FreezePane;
|
|
76
|
+
|
|
77
|
+
id?: number;
|
|
78
|
+
name?: string;
|
|
79
|
+
|
|
80
|
+
selection: GridSelection;
|
|
81
|
+
annotations?: Partial<Annotation>[];
|
|
82
|
+
scroll?: ScrollOffset;
|
|
83
|
+
|
|
84
|
+
visible?: boolean;
|
|
85
|
+
|
|
86
|
+
/** testing */
|
|
87
|
+
background_image?: string;
|
|
88
|
+
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* support for legacy sheet data
|
|
93
|
+
* (I think we can drop)
|
|
94
|
+
*/
|
|
95
|
+
export type LegacySerializedSheet = SerializedSheet & { primary_selection?: GridSelection }
|
|
@@ -0,0 +1,464 @@
|
|
|
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 { DataModel, ViewModel } from './data_model';
|
|
23
|
+
import { EventSource } from 'treb-utils';
|
|
24
|
+
import type { Sheet } from './sheet';
|
|
25
|
+
import type { BaseLayout } from '../layout/base_layout';
|
|
26
|
+
import { MouseDrag } from './drag_mask';
|
|
27
|
+
import type { GridOptions } from './grid_options';
|
|
28
|
+
import { ScaleEvent, ScaleControl } from './scale-control';
|
|
29
|
+
|
|
30
|
+
export interface ActivateSheetEvent {
|
|
31
|
+
type: 'activate-sheet';
|
|
32
|
+
sheet: Sheet;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface RenameSheetEvent {
|
|
36
|
+
type: 'rename-sheet';
|
|
37
|
+
sheet: Sheet;
|
|
38
|
+
name: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface ReorderSheetEvent {
|
|
42
|
+
type: 'reorder-sheet';
|
|
43
|
+
index: number;
|
|
44
|
+
move_before: number;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface AddSheetEvent {
|
|
48
|
+
type: 'add-sheet';
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface DeleteSheetEvent {
|
|
52
|
+
type: 'delete-sheet';
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface CancelEvent {
|
|
56
|
+
type: 'cancel';
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export type TabEvent
|
|
60
|
+
= CancelEvent
|
|
61
|
+
| ScaleEvent
|
|
62
|
+
| AddSheetEvent
|
|
63
|
+
| RenameSheetEvent
|
|
64
|
+
| DeleteSheetEvent
|
|
65
|
+
| ReorderSheetEvent
|
|
66
|
+
| ActivateSheetEvent
|
|
67
|
+
;
|
|
68
|
+
|
|
69
|
+
export interface StatsEntry {
|
|
70
|
+
label: string;
|
|
71
|
+
value: string;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* tabs for multiple sheets. at the bottom, atm (FIXME: options?)
|
|
76
|
+
*
|
|
77
|
+
* rename tabs (sheets) by double-clicking. this triggers a global
|
|
78
|
+
* rename over all cells and annotations.
|
|
79
|
+
*
|
|
80
|
+
* reorder tabs by dragging. reorders the array, but order is not
|
|
81
|
+
* material to any other module, so it's basically just housekeeping.
|
|
82
|
+
*
|
|
83
|
+
* add a new tab with a special (+) tab (last).
|
|
84
|
+
*
|
|
85
|
+
* FIXME: delete tabs... add an (x) to each tab? don't really want to
|
|
86
|
+
* do that. right-click is out. ??? [A: toolbar menu]
|
|
87
|
+
*
|
|
88
|
+
*/
|
|
89
|
+
export class TabBar extends EventSource<TabEvent> {
|
|
90
|
+
|
|
91
|
+
// private container?: HTMLElement;
|
|
92
|
+
private tab_container?: HTMLElement;
|
|
93
|
+
private scale_control?: ScaleControl;
|
|
94
|
+
private stats_panel?: HTMLDivElement;
|
|
95
|
+
|
|
96
|
+
private dragging = false;
|
|
97
|
+
|
|
98
|
+
private double_click_data: {
|
|
99
|
+
index?: number;
|
|
100
|
+
timeout?: number;
|
|
101
|
+
} = {};
|
|
102
|
+
|
|
103
|
+
// tslint:disable-next-line: variable-name
|
|
104
|
+
private _visible = false;
|
|
105
|
+
|
|
106
|
+
public get visible(): boolean {
|
|
107
|
+
return this._visible;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
public set stats_data(value: StatsEntry[]) {
|
|
111
|
+
if (this.stats_panel) {
|
|
112
|
+
this.stats_panel.innerText = ''; // clear
|
|
113
|
+
for (const entry of value) {
|
|
114
|
+
|
|
115
|
+
const label = document.createElement('span');
|
|
116
|
+
label.classList.add('treb-stats-label');
|
|
117
|
+
label.textContent = entry.label;
|
|
118
|
+
this.stats_panel.appendChild(label);
|
|
119
|
+
|
|
120
|
+
const figure = document.createElement('span');
|
|
121
|
+
figure.classList.add('treb-stats-value');
|
|
122
|
+
figure.textContent = entry.value;
|
|
123
|
+
this.stats_panel.appendChild(figure);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
private container: HTMLElement;
|
|
129
|
+
|
|
130
|
+
constructor(
|
|
131
|
+
private layout: BaseLayout,
|
|
132
|
+
private model: DataModel,
|
|
133
|
+
private view: ViewModel,
|
|
134
|
+
private options: GridOptions,
|
|
135
|
+
// private container: HTMLElement,
|
|
136
|
+
view_node: HTMLElement,
|
|
137
|
+
) {
|
|
138
|
+
|
|
139
|
+
super();
|
|
140
|
+
|
|
141
|
+
this.container = view_node.querySelector('.treb-spreadsheet-footer') as HTMLElement;
|
|
142
|
+
if (!this.container) {
|
|
143
|
+
throw new Error('missing container for tab bar');
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// if we're here, we have a tab bar. show unless we're on auto
|
|
147
|
+
if (options.tab_bar !== 'auto') {
|
|
148
|
+
this.container.removeAttribute('hidden');
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
this.tab_container = this.container.querySelector('.treb-spreadsheet-tabs') as HTMLDivElement;
|
|
152
|
+
|
|
153
|
+
this.container.addEventListener('click', event => {
|
|
154
|
+
const command = (event.target as HTMLElement)?.dataset.command;
|
|
155
|
+
if (command) {
|
|
156
|
+
event.stopPropagation();
|
|
157
|
+
event.preventDefault();
|
|
158
|
+
switch (command) {
|
|
159
|
+
case 'add-tab':
|
|
160
|
+
this.Publish({ type: 'add-sheet' });
|
|
161
|
+
break;
|
|
162
|
+
|
|
163
|
+
case 'delete-tab':
|
|
164
|
+
this.Publish({ type: 'delete-sheet' });
|
|
165
|
+
break;
|
|
166
|
+
|
|
167
|
+
default:
|
|
168
|
+
console.info('unhandled command', command);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
if (this.options.stats) {
|
|
174
|
+
this.stats_panel = this.container.querySelector('.treb-stats-panel') as HTMLDivElement;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (this.options.scale_control) {
|
|
178
|
+
const div = this.container.querySelector('.treb-scale-control') as HTMLDivElement;
|
|
179
|
+
this.scale_control = new ScaleControl(div);
|
|
180
|
+
this.scale_control.Subscribe((event: ScaleEvent) => {
|
|
181
|
+
this.Publish(event);
|
|
182
|
+
});
|
|
183
|
+
this.UpdateScale(this.options.initial_scale || 1); // so we only have to write the scaling routine once
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
public IsDoubleClick(index: number, timeout = 300): boolean {
|
|
189
|
+
|
|
190
|
+
if (this.double_click_data.index === index ) {
|
|
191
|
+
clearTimeout(this.double_click_data.timeout);
|
|
192
|
+
this.double_click_data.index = undefined;
|
|
193
|
+
this.double_click_data.timeout = undefined;
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (this.double_click_data.timeout) {
|
|
198
|
+
clearTimeout(this.double_click_data.timeout);
|
|
199
|
+
}
|
|
200
|
+
this.double_click_data.index = index;
|
|
201
|
+
this.double_click_data.timeout = window.setTimeout(() => {
|
|
202
|
+
this.double_click_data.index = undefined;
|
|
203
|
+
this.double_click_data.timeout = undefined;
|
|
204
|
+
}, timeout);
|
|
205
|
+
|
|
206
|
+
return false;
|
|
207
|
+
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
public Hide(): void {
|
|
211
|
+
this.Show(false);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
public Show(show = true): void {
|
|
215
|
+
if (!this.container) { return; }
|
|
216
|
+
|
|
217
|
+
this._visible = show;
|
|
218
|
+
|
|
219
|
+
if (show) {
|
|
220
|
+
this.container.removeAttribute('hidden');
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
this.container.setAttribute('hidden', '');
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
public SetActive(tab: HTMLElement, active: boolean): void {
|
|
229
|
+
if (active) {
|
|
230
|
+
// tab.classList.add('treb-selected');
|
|
231
|
+
tab.setAttribute('selected', '');
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
// tab.classList.remove('treb-selected');
|
|
235
|
+
tab.removeAttribute('selected');
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/** change scale if we have a scale label */
|
|
240
|
+
public UpdateScale(scale: number): void {
|
|
241
|
+
this.scale_control?.UpdateScale(scale * 100);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
public DoubleClickTab(event: MouseEvent, tab: HTMLElement, sheet: Sheet) {
|
|
245
|
+
|
|
246
|
+
tab.contentEditable = 'true';
|
|
247
|
+
|
|
248
|
+
// OK for shadow, seems to work as expected in all browsers
|
|
249
|
+
const selection = window.getSelection(); // OK for shadow
|
|
250
|
+
|
|
251
|
+
if (selection) {
|
|
252
|
+
selection.removeAllRanges();
|
|
253
|
+
const range = document.createRange();
|
|
254
|
+
range.selectNodeContents(tab);
|
|
255
|
+
selection.addRange(range);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
tab.addEventListener('keydown', (inner_event: KeyboardEvent) => {
|
|
259
|
+
switch (inner_event.key) {
|
|
260
|
+
case 'Enter':
|
|
261
|
+
// const name = tab.innerText.trim();
|
|
262
|
+
this.Publish({
|
|
263
|
+
type: 'rename-sheet',
|
|
264
|
+
name: tab.innerText.trim(),
|
|
265
|
+
sheet,
|
|
266
|
+
});
|
|
267
|
+
break;
|
|
268
|
+
|
|
269
|
+
case 'Escape':
|
|
270
|
+
tab.innerText = sheet.name;
|
|
271
|
+
this.Publish({ type: 'cancel' });
|
|
272
|
+
this.Update();
|
|
273
|
+
break;
|
|
274
|
+
|
|
275
|
+
default:
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
inner_event.stopPropagation();
|
|
279
|
+
inner_event.preventDefault();
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
tab.addEventListener('focusout', () => {
|
|
283
|
+
const name = tab.innerText.trim();
|
|
284
|
+
if (name !== sheet.name) {
|
|
285
|
+
this.Publish({ type: 'rename-sheet', name, sheet });
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
this.Update();
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
tab.focus();
|
|
293
|
+
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
public MouseDownTab(event: MouseEvent, tab: HTMLElement, sheet: Sheet, index: number, tabs: HTMLElement[]) {
|
|
297
|
+
|
|
298
|
+
event.stopPropagation();
|
|
299
|
+
event.preventDefault();
|
|
300
|
+
|
|
301
|
+
if (this.IsDoubleClick(index)) {
|
|
302
|
+
return; // seems to allow us to process double clicks normally...
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
this.Publish({ type: 'activate-sheet', sheet });
|
|
306
|
+
|
|
307
|
+
let rectangles = tabs.map((element) => element.getBoundingClientRect());
|
|
308
|
+
|
|
309
|
+
let order = index * 2 - 1;
|
|
310
|
+
|
|
311
|
+
// orginal
|
|
312
|
+
const left = rectangles[0].left;
|
|
313
|
+
const right = rectangles[rectangles.length - 1].right;
|
|
314
|
+
const top = rectangles[0].top;
|
|
315
|
+
const bottom = rectangles[0].bottom;
|
|
316
|
+
|
|
317
|
+
const min = -1;
|
|
318
|
+
const max = (rectangles.length - 1) * 2 + 1;
|
|
319
|
+
|
|
320
|
+
// see above re: dragging and activation. if the tabs aren't rebuilt,
|
|
321
|
+
// then the classes won't change.
|
|
322
|
+
|
|
323
|
+
for (const candidate of tabs) {
|
|
324
|
+
this.SetActive(candidate, candidate === tab);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
this.dragging = true;
|
|
328
|
+
|
|
329
|
+
MouseDrag(this.layout.mask, [], (move_event) => {
|
|
330
|
+
|
|
331
|
+
const [x, y] = [move_event.clientX, move_event.clientY];
|
|
332
|
+
if (y > top && y < bottom) {
|
|
333
|
+
let new_order = order;
|
|
334
|
+
if (x < left) { new_order = min; }
|
|
335
|
+
else if (x > right) { new_order = max; }
|
|
336
|
+
else {
|
|
337
|
+
for (let i = 0; i < rectangles.length; i++) {
|
|
338
|
+
const rectangle = rectangles[i];
|
|
339
|
+
if (x >= rectangle.left && x <= rectangle.right) {
|
|
340
|
+
if (i !== index) {
|
|
341
|
+
if (x >= rectangle.left + rectangle.width / 2) {
|
|
342
|
+
new_order = (i * 2) + 1;
|
|
343
|
+
}
|
|
344
|
+
else {
|
|
345
|
+
new_order = (i * 2) - 1;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
break;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
if (new_order !== order) {
|
|
353
|
+
order = new_order;
|
|
354
|
+
tab.style.order = order.toString();
|
|
355
|
+
rectangles = tabs.map((element) => element.getBoundingClientRect());
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
}, () => {
|
|
360
|
+
let current = index;
|
|
361
|
+
let move_before = (order + 1) / 2;
|
|
362
|
+
|
|
363
|
+
// console.info('set false')
|
|
364
|
+
this.dragging = false;
|
|
365
|
+
|
|
366
|
+
// the indexes we have are visible tabs only, so we may need
|
|
367
|
+
// to adjust if there are hidden tabs in between.
|
|
368
|
+
|
|
369
|
+
for (let i = 0; i < this.model.sheets.length; i++) {
|
|
370
|
+
if (!this.model.sheets.list[i].visible) {
|
|
371
|
+
if (current >= i) { current++; }
|
|
372
|
+
if (move_before >= i) { move_before++; }
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
if ((current === move_before) ||
|
|
377
|
+
(current === 0 && move_before <= 0) ||
|
|
378
|
+
(current === tabs.length - 1 && move_before >= tabs.length - 1)) {
|
|
379
|
+
|
|
380
|
+
// didn't change
|
|
381
|
+
}
|
|
382
|
+
else {
|
|
383
|
+
this.Publish({type: 'reorder-sheet', index: current, move_before});
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* update tabs from model.
|
|
392
|
+
*/
|
|
393
|
+
public Update(): void {
|
|
394
|
+
|
|
395
|
+
// this is a hack to normalize behavior if you try to re-order
|
|
396
|
+
// a tab that's not the active tab. what ordinarily happens is
|
|
397
|
+
// we start the drag, but then Update is called again which rebuilds
|
|
398
|
+
// tabs and throws out the old set.
|
|
399
|
+
|
|
400
|
+
// at the same time we want to activate on mousedown, not mouseup.
|
|
401
|
+
// so for the time being we just block the rebuild if we are dragging.
|
|
402
|
+
// longer term it's a FIXME.
|
|
403
|
+
|
|
404
|
+
if (this.dragging) {
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
if (this.options.tab_bar === 'auto') {
|
|
409
|
+
const visible_count = this.model.sheets.list.reduce((count, test) => test.visible ? count + 1 : count, 0);
|
|
410
|
+
if (visible_count <= 1) {
|
|
411
|
+
this.Show(false);
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
this.Show(true);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
if (!this.tab_container) {
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// clear
|
|
422
|
+
this.tab_container.innerText = '';
|
|
423
|
+
|
|
424
|
+
// we need to pass the full array to the drag function, so collect them
|
|
425
|
+
const tabs: HTMLElement[] = [];
|
|
426
|
+
|
|
427
|
+
for (const sheet of this.model.sheets.list) {
|
|
428
|
+
|
|
429
|
+
if (!sheet.visible) { continue; }
|
|
430
|
+
|
|
431
|
+
const index = tabs.length;
|
|
432
|
+
// const tab = document.createElement('div');
|
|
433
|
+
const tab = document.createElement('li');
|
|
434
|
+
|
|
435
|
+
// tab.classList.add('tab');
|
|
436
|
+
tab.style.order = (index * 2).toString();
|
|
437
|
+
tab.role = 'tab';
|
|
438
|
+
|
|
439
|
+
this.SetActive(tab, sheet === this.view.active_sheet);
|
|
440
|
+
|
|
441
|
+
const mousedown = (event: MouseEvent) => this.MouseDownTab(event, tab, sheet, index, tabs);
|
|
442
|
+
|
|
443
|
+
const doubleclick = (event: MouseEvent) => {
|
|
444
|
+
tab.removeEventListener('mousedown', mousedown);
|
|
445
|
+
tab.removeEventListener('dblclick', doubleclick);
|
|
446
|
+
this.DoubleClickTab(event, tab, sheet);
|
|
447
|
+
};
|
|
448
|
+
|
|
449
|
+
// you need the inner span for ellipsis, if we want that
|
|
450
|
+
|
|
451
|
+
tab.textContent = sheet.name;
|
|
452
|
+
// tab.innerHTML = `<span>${sheet.name}</span>`;
|
|
453
|
+
|
|
454
|
+
tab.addEventListener('dblclick', doubleclick);
|
|
455
|
+
tab.addEventListener('mousedown', mousedown);
|
|
456
|
+
|
|
457
|
+
this.tab_container.appendChild(tab);
|
|
458
|
+
tabs.push(tab);
|
|
459
|
+
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
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 { Point, Size, Position } from 'treb-base-types';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* tile adds some metadata to canvas
|
|
26
|
+
*
|
|
27
|
+
* FIXME: there might be some performance cost with this, versus a wrapper
|
|
28
|
+
* or container class/interface that just holds the canvas.
|
|
29
|
+
*/
|
|
30
|
+
export interface Tile extends HTMLCanvasElement {
|
|
31
|
+
|
|
32
|
+
/** contents have changed, needs repainting */
|
|
33
|
+
dirty: boolean;
|
|
34
|
+
|
|
35
|
+
/** never painted or layout has changed: repaint everything */
|
|
36
|
+
needs_full_repaint: boolean;
|
|
37
|
+
|
|
38
|
+
/** position in the grid, in grid rows/columns */
|
|
39
|
+
tile_position: Position;
|
|
40
|
+
|
|
41
|
+
/** first cell in the tile */
|
|
42
|
+
first_cell: Position;
|
|
43
|
+
|
|
44
|
+
/** last cell in the tile, more useful than extent */
|
|
45
|
+
last_cell: Position;
|
|
46
|
+
|
|
47
|
+
/** position in the grid, in pixels */
|
|
48
|
+
pixel_start: Point;
|
|
49
|
+
|
|
50
|
+
/** position in the grid, in pixels */
|
|
51
|
+
pixel_end: Point;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* tile size in pixels, matching css height/width. this is
|
|
55
|
+
* different than the _canvas_ height/width, which is scaled
|
|
56
|
+
* to dpr for high-dpi displays.
|
|
57
|
+
*/
|
|
58
|
+
logical_size: Size;
|
|
59
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
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 { Area } from 'treb-base-types';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* trying to split data management from the grid, we are updating the
|
|
26
|
+
* command queue so that (some/most) methods return hints as to what
|
|
27
|
+
* needs to update: a nonvisible grid can just ignore this, but the
|
|
28
|
+
* visible grid can use it to trigger layout/repaint/etc.
|
|
29
|
+
*/
|
|
30
|
+
export interface UpdateFlags {
|
|
31
|
+
|
|
32
|
+
/** sheet names or order have changed, update the tab bar */
|
|
33
|
+
sheets?: boolean;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* structure refers to rows/columns/sheets -- something has been
|
|
37
|
+
* added, removed, or resized
|
|
38
|
+
*/
|
|
39
|
+
structure?: boolean;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* on sheet change, hide hover info -- hyperlink, note, &c
|
|
43
|
+
*/
|
|
44
|
+
active_sheet?: boolean;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* formula -- we might need to update the formula bar
|
|
48
|
+
*/
|
|
49
|
+
formula?: boolean;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* layout is changing. use this as a proxy for the old "queue layout update"
|
|
53
|
+
*/
|
|
54
|
+
layout?: boolean;
|
|
55
|
+
|
|
56
|
+
/** non-active sheets updated. we set flags to update layout on activate */
|
|
57
|
+
pending?: number[];
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* this is only used by the setheaders command, which needs to come
|
|
61
|
+
* out. so this should also come out.
|
|
62
|
+
*/
|
|
63
|
+
repaint?: boolean;
|
|
64
|
+
|
|
65
|
+
data_event?: boolean;
|
|
66
|
+
style_event?: boolean;
|
|
67
|
+
structure_event?: boolean;
|
|
68
|
+
structure_rebuild_required?: boolean;
|
|
69
|
+
|
|
70
|
+
render_area?: Area;
|
|
71
|
+
data_area?: Area;
|
|
72
|
+
style_area?: Area;
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
}
|