@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,473 @@
|
|
|
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 { Yield } from 'treb-utils';
|
|
23
|
+
|
|
24
|
+
import { DOMUtilities } from '../util/dom_utilities';
|
|
25
|
+
import type { Theme } from 'treb-base-types';
|
|
26
|
+
import { FormulaEditorBase, FormulaEditorEvent } from './formula_editor_base';
|
|
27
|
+
import type { GridOptions } from '../types/grid_options';
|
|
28
|
+
import type { Autocomplete } from './autocomplete';
|
|
29
|
+
import type { DataModel, ViewModel } from '../types/data_model';
|
|
30
|
+
import type { Parser } from 'treb-parser';
|
|
31
|
+
|
|
32
|
+
export interface FormulaBarResizeEvent {
|
|
33
|
+
type: 'formula-bar-resize';
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface FormulaButtonEvent {
|
|
37
|
+
type: 'formula-button';
|
|
38
|
+
formula?: string;
|
|
39
|
+
cursor_position?: number;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface AddressLabelEvent {
|
|
43
|
+
type: 'address-label-event';
|
|
44
|
+
text?: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export type FormulaBar2Event
|
|
48
|
+
= FormulaEditorEvent
|
|
49
|
+
| FormulaButtonEvent
|
|
50
|
+
| FormulaBarResizeEvent
|
|
51
|
+
| AddressLabelEvent
|
|
52
|
+
;
|
|
53
|
+
|
|
54
|
+
export class FormulaBar extends FormulaEditorBase<FormulaBar2Event> {
|
|
55
|
+
|
|
56
|
+
/** is the _editor_ currently focused */
|
|
57
|
+
// tslint:disable-next-line:variable-name
|
|
58
|
+
public focused_ = false;
|
|
59
|
+
|
|
60
|
+
/** accessor for focused field */
|
|
61
|
+
public get focused(): boolean { return this.focused_; }
|
|
62
|
+
|
|
63
|
+
/** address label (may also show other things... ?) */
|
|
64
|
+
private address_label_container: HTMLDivElement;
|
|
65
|
+
|
|
66
|
+
/** address label (may also show other things... ?) */
|
|
67
|
+
private address_label: HTMLDivElement;
|
|
68
|
+
|
|
69
|
+
/** the function button (optional?) */
|
|
70
|
+
private button!: HTMLButtonElement;
|
|
71
|
+
|
|
72
|
+
/** */
|
|
73
|
+
private expand_button!: HTMLButtonElement;
|
|
74
|
+
|
|
75
|
+
/** corner for resizing formula editor */
|
|
76
|
+
private drag_corner!: HTMLDivElement;
|
|
77
|
+
|
|
78
|
+
/** for math */
|
|
79
|
+
private lines = 1;
|
|
80
|
+
|
|
81
|
+
private last_formula = '';
|
|
82
|
+
|
|
83
|
+
private label_update_timer = 0;
|
|
84
|
+
|
|
85
|
+
/** get formula text */
|
|
86
|
+
public get formula(): string {
|
|
87
|
+
return this.editor_node ? this.editor_node.textContent || '' : '';
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** set formula text */
|
|
91
|
+
public set formula(text: string) {
|
|
92
|
+
if (this.editor_node) {
|
|
93
|
+
this.editor_node.textContent = text;
|
|
94
|
+
this.last_reconstructed_text = '';
|
|
95
|
+
}
|
|
96
|
+
this.last_formula = text;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** get address label text */
|
|
100
|
+
public get label(): string {
|
|
101
|
+
return this.address_label?.textContent || '';
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* set address label text. if the label is too long for the box,
|
|
106
|
+
* add a title attribute for a tooltip.
|
|
107
|
+
*/
|
|
108
|
+
public set label(text: string) {
|
|
109
|
+
if (!text.trim().length) {
|
|
110
|
+
this.address_label.innerHTML = ' ';
|
|
111
|
+
this.address_label.removeAttribute('title');
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
this.address_label.textContent = text;
|
|
115
|
+
|
|
116
|
+
if (!this.label_update_timer) {
|
|
117
|
+
this.label_update_timer = requestAnimationFrame(() => {
|
|
118
|
+
this.label_update_timer = 0;
|
|
119
|
+
|
|
120
|
+
// should this be in a Yield callback? need to check IE11...
|
|
121
|
+
// yes
|
|
122
|
+
|
|
123
|
+
if (this.address_label.scrollWidth > this.address_label.offsetWidth) {
|
|
124
|
+
this.address_label.setAttribute('title', text);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
this.address_label.removeAttribute('title');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** toggle editable property: supports locked cells */
|
|
137
|
+
public set editable(editable: boolean) {
|
|
138
|
+
if (!this.editor_node || !this.container_node) return;
|
|
139
|
+
|
|
140
|
+
if (editable) {
|
|
141
|
+
this.editor_node.setAttribute('contenteditable', 'true'); // is that required?
|
|
142
|
+
this.container_node.removeAttribute('locked');
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
this.editor_node.removeAttribute('contenteditable');
|
|
146
|
+
this.container_node.setAttribute('locked', '');
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
constructor(
|
|
152
|
+
private container: HTMLElement,
|
|
153
|
+
parser: Parser,
|
|
154
|
+
theme: Theme,
|
|
155
|
+
model: DataModel,
|
|
156
|
+
view: ViewModel,
|
|
157
|
+
private options: GridOptions,
|
|
158
|
+
autocomplete: Autocomplete,
|
|
159
|
+
) {
|
|
160
|
+
|
|
161
|
+
super(parser, theme, model, view, autocomplete);
|
|
162
|
+
|
|
163
|
+
const inner_node = container.querySelector('.treb-formula-bar') as HTMLElement;
|
|
164
|
+
inner_node.removeAttribute('hidden');
|
|
165
|
+
|
|
166
|
+
this.address_label_container = inner_node.querySelector('.treb-address-label') as HTMLDivElement;
|
|
167
|
+
this.address_label = this.address_label_container.firstElementChild as HTMLDivElement;
|
|
168
|
+
|
|
169
|
+
this.InitAddressLabel();
|
|
170
|
+
|
|
171
|
+
if (this.options.insert_function_button) {
|
|
172
|
+
this.button = DOMUtilities.Create<HTMLButtonElement>('button', 'formula-button', inner_node);
|
|
173
|
+
this.button.addEventListener('click', () => {
|
|
174
|
+
const formula: string = this.editor_node ? this.editor_node.textContent || '' : '';
|
|
175
|
+
this.Publish({ type: 'formula-button', formula });
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
this.container_node = container.querySelector('.treb-editor-container') as HTMLDivElement;
|
|
180
|
+
this.editor_node = this.container_node.firstElementChild as HTMLDivElement;
|
|
181
|
+
|
|
182
|
+
//
|
|
183
|
+
// change the default back. this was changed when we were trying to figure
|
|
184
|
+
// out what was happening with IME, but it had nothing to do with spellcheck.
|
|
185
|
+
//
|
|
186
|
+
this.editor_node.spellcheck = false; // change the default back
|
|
187
|
+
|
|
188
|
+
this.editor_node.addEventListener('focusin', () => {
|
|
189
|
+
|
|
190
|
+
// can't happen
|
|
191
|
+
if (!this.editor_node) { return; }
|
|
192
|
+
|
|
193
|
+
// console.info('focus in');
|
|
194
|
+
|
|
195
|
+
let text = this.editor_node.textContent || '';
|
|
196
|
+
|
|
197
|
+
if (text[0] === '{' && text[text.length - 1] === '}') {
|
|
198
|
+
text = text.substr(1, text.length - 2);
|
|
199
|
+
this.editor_node.textContent = text;
|
|
200
|
+
this.last_reconstructed_text = '';
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
this.editor_node.spellcheck = (text[0] !== '='); // true except for functions
|
|
204
|
+
|
|
205
|
+
this.autocomplete.ResetBlock();
|
|
206
|
+
|
|
207
|
+
/*
|
|
208
|
+
const fragment = this.Reconstruct();
|
|
209
|
+
if (fragment && this.editor_node) {
|
|
210
|
+
this.editor_node.textContent = '';
|
|
211
|
+
this.editor_node.appendChild(fragment);
|
|
212
|
+
}
|
|
213
|
+
*/
|
|
214
|
+
Yield().then(() => {
|
|
215
|
+
// this.Reconstruct(true);
|
|
216
|
+
this.Reconstruct();
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
const dependencies = this.ListDependencies();
|
|
220
|
+
|
|
221
|
+
this.Publish([
|
|
222
|
+
{ type: 'start-editing', editor: 'formula-bar' },
|
|
223
|
+
{ type: 'update', text, cell: this.active_cell, dependencies },
|
|
224
|
+
// { type: 'retain-focus', focus: true },
|
|
225
|
+
]);
|
|
226
|
+
|
|
227
|
+
this.focused_ = true;
|
|
228
|
+
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
this.editor_node.addEventListener('focusout', () => {
|
|
232
|
+
|
|
233
|
+
if (this.selecting) {
|
|
234
|
+
console.info('focusout, but selecting...');
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// console.info('focus out');
|
|
238
|
+
|
|
239
|
+
this.autocomplete.Hide();
|
|
240
|
+
this.Publish([
|
|
241
|
+
{ type: 'stop-editing' },
|
|
242
|
+
// { type: 'retain-focus', focus: false },
|
|
243
|
+
]);
|
|
244
|
+
this.focused_ = false;
|
|
245
|
+
|
|
246
|
+
if (this.editor_node) {
|
|
247
|
+
this.editor_node.spellcheck = false; // for firefox
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
this.editor_node.addEventListener('keydown', (event) => this.FormulaKeyDown(event));
|
|
253
|
+
this.editor_node.addEventListener('keyup', (event) => this.FormulaKeyUp(event));
|
|
254
|
+
|
|
255
|
+
this.editor_node.addEventListener('input', (event: Event) => {
|
|
256
|
+
|
|
257
|
+
if (event instanceof InputEvent && event.isComposing) {
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
this.Reconstruct();
|
|
262
|
+
this.UpdateSelectState();
|
|
263
|
+
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
if (this.options.expand_formula_button) {
|
|
267
|
+
this.expand_button = DOMUtilities.Create<HTMLButtonElement>('button', 'expand-button', inner_node);
|
|
268
|
+
this.expand_button.addEventListener('click', (event: MouseEvent) => {
|
|
269
|
+
event.stopPropagation();
|
|
270
|
+
event.preventDefault();
|
|
271
|
+
if (this.editor_node) {
|
|
272
|
+
this.editor_node.scrollTop = 0;
|
|
273
|
+
}
|
|
274
|
+
// inner_node.classList.toggle('expanded');
|
|
275
|
+
if (inner_node.hasAttribute('expanded')) {
|
|
276
|
+
inner_node.removeAttribute('expanded');
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
inner_node.setAttribute('expanded', '');
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
public IsElement(element: HTMLElement): boolean {
|
|
287
|
+
return element === this.editor_node;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
public InitAddressLabel() {
|
|
291
|
+
|
|
292
|
+
this.address_label.contentEditable = 'true';
|
|
293
|
+
this.address_label.spellcheck = false;
|
|
294
|
+
|
|
295
|
+
// on focus, select all
|
|
296
|
+
// Q: do we do this in other places? we should consolidate
|
|
297
|
+
// A: I don't think we do just this, usually there's additional logic for % and such
|
|
298
|
+
|
|
299
|
+
this.address_label.addEventListener('focusin', (event) => {
|
|
300
|
+
|
|
301
|
+
// FIXME: close any open editors? (...)
|
|
302
|
+
|
|
303
|
+
// we're now doing this async for all browsers... it's only really
|
|
304
|
+
// necessary for IE11 and safari, but doesn't hurt
|
|
305
|
+
|
|
306
|
+
requestAnimationFrame(() => {
|
|
307
|
+
if ((document.body as any).createTextRange) {
|
|
308
|
+
const range = (document.body as any).createTextRange();
|
|
309
|
+
range.moveToElementText(this.address_label);
|
|
310
|
+
range.select();
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
const selection = window.getSelection();
|
|
314
|
+
const range = document.createRange();
|
|
315
|
+
range.selectNodeContents(this.address_label);
|
|
316
|
+
selection?.removeAllRanges();
|
|
317
|
+
selection?.addRange(range);
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
this.address_label.addEventListener('keydown', (event) => {
|
|
324
|
+
switch (event.key) {
|
|
325
|
+
|
|
326
|
+
case 'Enter':
|
|
327
|
+
event.stopPropagation();
|
|
328
|
+
event.preventDefault();
|
|
329
|
+
this.Publish({
|
|
330
|
+
type: 'address-label-event',
|
|
331
|
+
text: this.address_label.textContent || undefined,
|
|
332
|
+
});
|
|
333
|
+
break;
|
|
334
|
+
|
|
335
|
+
case 'Esc':
|
|
336
|
+
case 'Escape':
|
|
337
|
+
event.stopPropagation();
|
|
338
|
+
event.preventDefault();
|
|
339
|
+
this.Publish({ type: 'address-label-event' });
|
|
340
|
+
break;
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* focuses the formula editor. this is intended to be called after a
|
|
348
|
+
* range selection, so we can continue editing.
|
|
349
|
+
*/
|
|
350
|
+
public FocusEditor(): void {
|
|
351
|
+
if (this.editor_node) {
|
|
352
|
+
this.editor_node.focus();
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/*
|
|
357
|
+
public UpdateTheme(): void {
|
|
358
|
+
|
|
359
|
+
let font_size = this.theme.formula_bar_font_size || null;
|
|
360
|
+
|
|
361
|
+
if (typeof font_size === 'number') {
|
|
362
|
+
font_size = `${font_size}pt`;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// all these are applied to the container; font is then inherited.
|
|
366
|
+
|
|
367
|
+
this.address_label_container.style.fontFamily = this.theme.formula_bar_font_face || '';
|
|
368
|
+
this.address_label_container.style.fontSize = font_size || '';
|
|
369
|
+
this.address_label_container.style.fontWeight = '400'; // FIXME
|
|
370
|
+
|
|
371
|
+
this.address_label_container.style.backgroundColor = this.theme.formula_bar_background_color || '';
|
|
372
|
+
this.address_label_container.style.color = this.theme.formula_bar_color || '';
|
|
373
|
+
|
|
374
|
+
if (this.container_node) {
|
|
375
|
+
this.container_node.style.fontFamily = this.theme.formula_bar_font_face || '';
|
|
376
|
+
this.container_node.style.fontSize = font_size || '';
|
|
377
|
+
this.container_node.style.fontWeight = '400'; // FIXME
|
|
378
|
+
this.container_node.style.backgroundColor = this.theme.formula_bar_background_color || '';
|
|
379
|
+
this.container_node.style.color = this.theme.formula_bar_color || '';
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
if (this.autocomplete) {
|
|
383
|
+
this.autocomplete.UpdateTheme();
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
}
|
|
387
|
+
*/
|
|
388
|
+
|
|
389
|
+
private GetTextContent(node: Node) {
|
|
390
|
+
|
|
391
|
+
const children = node.childNodes;
|
|
392
|
+
const buffer: string[] = [];
|
|
393
|
+
for (let i = 0; i < children.length; i++) {
|
|
394
|
+
const child = children[i];
|
|
395
|
+
switch (child.nodeType) {
|
|
396
|
+
case Node.ELEMENT_NODE:
|
|
397
|
+
buffer.push(...this.GetTextContent(child));
|
|
398
|
+
if (child instanceof Element && child.tagName === 'DIV') {
|
|
399
|
+
buffer.push('\n');
|
|
400
|
+
}
|
|
401
|
+
break;
|
|
402
|
+
|
|
403
|
+
case Node.TEXT_NODE:
|
|
404
|
+
if (child.nodeValue) { buffer.push(child.nodeValue); }
|
|
405
|
+
break;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
return buffer;
|
|
409
|
+
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
private FormulaKeyDown(event: KeyboardEvent){
|
|
413
|
+
|
|
414
|
+
const ac_result = this.autocomplete.HandleKey('keydown', event);
|
|
415
|
+
if (ac_result.accept) this.AcceptAutocomplete(ac_result);
|
|
416
|
+
if (ac_result.handled) return;
|
|
417
|
+
|
|
418
|
+
switch (event.key){
|
|
419
|
+
case 'Enter':
|
|
420
|
+
case 'Tab':
|
|
421
|
+
{
|
|
422
|
+
this.selecting_ = false;
|
|
423
|
+
const array = (event.key === 'Enter' && event.ctrlKey && event.shiftKey);
|
|
424
|
+
|
|
425
|
+
const text = (this.editor_node ?
|
|
426
|
+
this.GetTextContent(this.editor_node).join('') : '').trim();
|
|
427
|
+
|
|
428
|
+
this.Publish({
|
|
429
|
+
type: 'commit',
|
|
430
|
+
selection: this.selection,
|
|
431
|
+
value: text,
|
|
432
|
+
event,
|
|
433
|
+
array,
|
|
434
|
+
});
|
|
435
|
+
this.FlushReference();
|
|
436
|
+
}
|
|
437
|
+
break;
|
|
438
|
+
|
|
439
|
+
case 'Escape':
|
|
440
|
+
case 'Esc':
|
|
441
|
+
this.selecting_ = false;
|
|
442
|
+
this.Publish({ type: 'discard' });
|
|
443
|
+
this.FlushReference();
|
|
444
|
+
break;
|
|
445
|
+
|
|
446
|
+
default:
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
event.stopPropagation();
|
|
451
|
+
event.preventDefault();
|
|
452
|
+
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
private FormulaKeyUp(event: KeyboardEvent){
|
|
456
|
+
|
|
457
|
+
const ac_result = this.autocomplete.HandleKey('keyup', event);
|
|
458
|
+
if (ac_result.handled) return;
|
|
459
|
+
this.FlushReference();
|
|
460
|
+
|
|
461
|
+
// because there are no input events, we have to try this one -- note
|
|
462
|
+
// we still won't capture pastes, FIXME (add handlers?)
|
|
463
|
+
|
|
464
|
+
//if (this.trident) {
|
|
465
|
+
// this.UpdateSelectState();
|
|
466
|
+
// this.Reconstruct();
|
|
467
|
+
//}
|
|
468
|
+
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
}
|
|
473
|
+
|