@trebco/treb 27.12.1 → 28.0.5
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/README.md +6 -0
- package/dist/treb-spreadsheet-light.mjs +16 -0
- package/dist/treb-spreadsheet.mjs +14 -12
- package/dist/treb.d.ts +31 -3
- package/esbuild-custom-element.mjs +3 -1
- package/package.json +4 -4
- package/treb-base-types/src/dom-utilities.ts +157 -19
- package/treb-base-types/src/theme.ts +5 -4
- package/treb-charts/src/renderer.ts +4 -58
- package/treb-embed/markup/layout.html +4 -0
- package/treb-embed/src/custom-element/spreadsheet-constructor.ts +131 -87
- package/treb-embed/src/embedded-spreadsheet.ts +146 -111
- package/treb-embed/src/options.ts +9 -0
- package/treb-embed/src/spinner.ts +5 -3
- package/treb-embed/src/toolbar-message.ts +5 -0
- package/treb-embed/style/layout.scss +65 -1
- package/treb-grid/src/editors/autocomplete.ts +24 -13
- package/treb-grid/src/editors/editor.ts +43 -139
- package/treb-grid/src/editors/external_editor.ts +1 -1
- package/treb-grid/src/editors/formula_bar.ts +24 -24
- package/treb-grid/src/editors/overlay_editor.ts +6 -2
- package/treb-grid/src/layout/base_layout.ts +34 -25
- package/treb-grid/src/layout/grid_layout.ts +20 -20
- package/treb-grid/src/render/selection-renderer.ts +3 -3
- package/treb-grid/src/render/svg_header_overlay.ts +6 -4
- package/treb-grid/src/render/svg_selection_block.ts +10 -7
- package/treb-grid/src/types/grid.ts +80 -81
- package/treb-grid/src/types/scale-control.ts +69 -81
- package/treb-grid/src/types/sheet.ts +3 -52
- package/treb-grid/src/types/tab_bar.ts +27 -13
- package/treb-grid/src/util/fontmetrics2.ts +24 -21
- package/treb-utils/src/event_source.ts +23 -23
- package/treb-utils/src/index.ts +2 -2
- package/treb-utils/src/measurement.ts +24 -24
- package/treb-utils/src/serialize_html.ts +25 -21
- package/treb-utils/src/dispatch.ts +0 -57
- package/treb-utils/src/resizable.ts +0 -159
|
@@ -26,7 +26,7 @@ import type { BaseLayout } from '../layout/base_layout';
|
|
|
26
26
|
import { MouseDrag } from './drag_mask';
|
|
27
27
|
import type { GridOptions } from './grid_options';
|
|
28
28
|
import { type ScaleEvent, ScaleControl } from './scale-control';
|
|
29
|
-
import {
|
|
29
|
+
import { DOMContext } from 'treb-base-types';
|
|
30
30
|
|
|
31
31
|
export interface ActivateSheetEvent {
|
|
32
32
|
type: 'activate-sheet';
|
|
@@ -113,17 +113,22 @@ export class TabBar extends EventSource<TabEvent> {
|
|
|
113
113
|
this.stats_panel.innerText = ''; // clear
|
|
114
114
|
for (const entry of value) {
|
|
115
115
|
|
|
116
|
-
|
|
117
|
-
|
|
116
|
+
this.DOM.Create('span', 'treb-stats-label', this.stats_panel, {
|
|
117
|
+
text: entry.label
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
this.DOM.Create('span', 'treb-stats-value', this.stats_panel, {
|
|
121
|
+
text: entry.value,
|
|
122
|
+
});
|
|
118
123
|
|
|
119
|
-
const figure = DOMUtilities.Create('span', 'treb-stats-value', this.stats_panel);
|
|
120
|
-
figure.textContent = entry.value;
|
|
121
124
|
}
|
|
122
125
|
}
|
|
123
126
|
}
|
|
124
127
|
|
|
125
128
|
private container: HTMLElement;
|
|
126
129
|
|
|
130
|
+
private DOM: DOMContext;
|
|
131
|
+
|
|
127
132
|
constructor(
|
|
128
133
|
private layout: BaseLayout,
|
|
129
134
|
private model: DataModel,
|
|
@@ -135,6 +140,8 @@ export class TabBar extends EventSource<TabEvent> {
|
|
|
135
140
|
|
|
136
141
|
super();
|
|
137
142
|
|
|
143
|
+
this.DOM = DOMContext.GetInstance(view_node.ownerDocument);
|
|
144
|
+
|
|
138
145
|
this.container = view_node.querySelector('.treb-spreadsheet-footer') as HTMLElement;
|
|
139
146
|
if (!this.container) {
|
|
140
147
|
throw new Error('missing container for tab bar');
|
|
@@ -195,6 +202,10 @@ export class TabBar extends EventSource<TabEvent> {
|
|
|
195
202
|
clearTimeout(this.double_click_data.timeout);
|
|
196
203
|
}
|
|
197
204
|
this.double_click_data.index = index;
|
|
205
|
+
|
|
206
|
+
// I don't think the window instance matters for this,
|
|
207
|
+
// but perhaps it's worth using DOM just for consistency
|
|
208
|
+
|
|
198
209
|
this.double_click_data.timeout = window.setTimeout(() => {
|
|
199
210
|
this.double_click_data.index = undefined;
|
|
200
211
|
this.double_click_data.timeout = undefined;
|
|
@@ -242,14 +253,17 @@ export class TabBar extends EventSource<TabEvent> {
|
|
|
242
253
|
|
|
243
254
|
tab.contentEditable = 'true';
|
|
244
255
|
|
|
245
|
-
|
|
246
|
-
|
|
256
|
+
if (this.DOM.doc) {
|
|
257
|
+
|
|
258
|
+
const selection = this.DOM.GetSelection();
|
|
259
|
+
|
|
260
|
+
if (selection) {
|
|
261
|
+
selection.removeAllRanges();
|
|
262
|
+
const range = this.DOM.doc.createRange();
|
|
263
|
+
range.selectNodeContents(tab);
|
|
264
|
+
selection.addRange(range);
|
|
265
|
+
}
|
|
247
266
|
|
|
248
|
-
if (selection) {
|
|
249
|
-
selection.removeAllRanges();
|
|
250
|
-
const range = document.createRange();
|
|
251
|
-
range.selectNodeContents(tab);
|
|
252
|
-
selection.addRange(range);
|
|
253
267
|
}
|
|
254
268
|
|
|
255
269
|
tab.addEventListener('keydown', (inner_event: KeyboardEvent) => {
|
|
@@ -448,7 +462,7 @@ export class TabBar extends EventSource<TabEvent> {
|
|
|
448
462
|
if (!sheet.visible) { continue; }
|
|
449
463
|
|
|
450
464
|
const index = tabs.length;
|
|
451
|
-
const tab =
|
|
465
|
+
const tab = this.DOM.Create('li');
|
|
452
466
|
tab.setAttribute('tabindex', '0');
|
|
453
467
|
|
|
454
468
|
// tab.classList.add('tab');
|
|
@@ -1,24 +1,24 @@
|
|
|
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
|
-
|
|
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
22
|
export interface FontMetrics2 {
|
|
23
23
|
ascender: number;
|
|
24
24
|
descender: number;
|
|
@@ -63,6 +63,9 @@ export class FontMetricsFactory {
|
|
|
63
63
|
// what we're doing now is calculating -- we get the base size
|
|
64
64
|
// from theme and if we see em or % we scale manually.
|
|
65
65
|
|
|
66
|
+
// based on the above, we don't need to worry about which
|
|
67
|
+
// document we're using. but we probably should just to be consistent.
|
|
68
|
+
|
|
66
69
|
}
|
|
67
70
|
|
|
68
71
|
/* *
|
|
@@ -1,25 +1,25 @@
|
|
|
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 './dispatch';
|
|
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 './dispatch';
|
|
23
23
|
// import { IEventSource } from './ievent_source';
|
|
24
24
|
|
|
25
25
|
let subscription_token_generator = 1000;
|
|
@@ -90,7 +90,7 @@ export class EventSource<T> { // implements IEventSource<T> {
|
|
|
90
90
|
if (!this.dispatched) {
|
|
91
91
|
this.dispatched = true;
|
|
92
92
|
|
|
93
|
-
|
|
93
|
+
Promise.resolve().then(() => {
|
|
94
94
|
|
|
95
95
|
const events = this.queue.slice(0);
|
|
96
96
|
this.dispatched = false;
|
package/treb-utils/src/index.ts
CHANGED
|
@@ -19,10 +19,10 @@
|
|
|
19
19
|
*
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
export * from './dispatch';
|
|
22
|
+
// export * from './dispatch';
|
|
23
23
|
export * from './event_source';
|
|
24
24
|
export * from './ievent_source';
|
|
25
|
-
export * from './resizable';
|
|
25
|
+
// export * from './resizable';
|
|
26
26
|
export * from './measurement';
|
|
27
27
|
// export * from './color';
|
|
28
28
|
export * from './serialize_html';
|
|
@@ -1,24 +1,24 @@
|
|
|
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
|
-
|
|
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
22
|
/** size, really */
|
|
23
23
|
export interface Metrics {
|
|
24
24
|
width: number;
|
|
@@ -120,7 +120,7 @@ export class Measurement {
|
|
|
120
120
|
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
|
|
123
|
+
/* *
|
|
124
124
|
* check if font is loaded, based on the theory that the alternatives
|
|
125
125
|
* will be different sizes. note that this probably doesn't test weights
|
|
126
126
|
* or italics properly, as those can be emulated without the specific face.
|
|
@@ -131,7 +131,7 @@ export class Measurement {
|
|
|
131
131
|
* @param font_face
|
|
132
132
|
* @param italic
|
|
133
133
|
* @param bold
|
|
134
|
-
|
|
134
|
+
* /
|
|
135
135
|
public static FontLoaded(font_face: string, italic = false, weight = 400): boolean {
|
|
136
136
|
const face = `${italic ? 'italic' : ''} ${weight} 20pt ${font_face}`;
|
|
137
137
|
const m1 = this.MeasureText(`${face}, sans-serif`, `check font`);
|
|
@@ -139,6 +139,7 @@ export class Measurement {
|
|
|
139
139
|
const m3 = this.MeasureText(`${face}, monospace`, `check font`);
|
|
140
140
|
return (m1.width === m2.width && m2.width === m3.width);
|
|
141
141
|
}
|
|
142
|
+
*/
|
|
142
143
|
|
|
143
144
|
/**
|
|
144
145
|
* measure width, height of text, accounting for rotation
|
|
@@ -169,6 +170,5 @@ export class Measurement {
|
|
|
169
170
|
|
|
170
171
|
}
|
|
171
172
|
|
|
172
|
-
|
|
173
173
|
}
|
|
174
174
|
|
|
@@ -1,24 +1,24 @@
|
|
|
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
|
-
|
|
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
22
|
interface StringMap {
|
|
23
23
|
[index: string]: string;
|
|
24
24
|
}
|
|
@@ -95,6 +95,10 @@ export const SerializeHTML = (node: Element) => {
|
|
|
95
95
|
|
|
96
96
|
const defaults: StringMap = {};
|
|
97
97
|
|
|
98
|
+
// regarding document, in this case we're creating an iframe
|
|
99
|
+
// specifically for isolation, and adding it to "document".
|
|
100
|
+
// there's no reason to require the context document here (I think).
|
|
101
|
+
|
|
98
102
|
const iframe = document.createElement('iframe');
|
|
99
103
|
iframe.style.width = '10px';
|
|
100
104
|
iframe.style.height = '10px';
|
|
@@ -1,57 +0,0 @@
|
|
|
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
|
-
* UPDATE: dropping dispatch altogether. there were really very few
|
|
24
|
-
* cases where queue length > 1, so it seems like unecessary overhead.
|
|
25
|
-
*
|
|
26
|
-
* it's still somewhat useful to have an interface, in the event we
|
|
27
|
-
* change this again, so keep using the Yield() function.
|
|
28
|
-
*
|
|
29
|
-
* TODO: is anyone using the callback version? could drop...
|
|
30
|
-
*
|
|
31
|
-
* I'm guessing no one uses it, because it's broken amd we never noticed
|
|
32
|
-
*/
|
|
33
|
-
|
|
34
|
-
/* *
|
|
35
|
-
* yield and then call the passed function
|
|
36
|
-
* /
|
|
37
|
-
export function Yield(fn: () => void): void;
|
|
38
|
-
|
|
39
|
-
/ * *
|
|
40
|
-
* returns a promise that resolves after yield
|
|
41
|
-
* /
|
|
42
|
-
export function Yield(): Promise<void>;
|
|
43
|
-
|
|
44
|
-
/ * * implementation * /
|
|
45
|
-
export function Yield(fn?: () => void) {
|
|
46
|
-
return fn ? Promise.resolve().then(fn) : Promise.resolve();
|
|
47
|
-
}
|
|
48
|
-
*/
|
|
49
|
-
|
|
50
|
-
/* for perf testing, we don't need this anymore
|
|
51
|
-
(self as any).__dispatcher_instance = {
|
|
52
|
-
Call: Yield
|
|
53
|
-
}
|
|
54
|
-
*/
|
|
55
|
-
|
|
56
|
-
export const Yield = () => Promise.resolve();
|
|
57
|
-
|
|
@@ -1,159 +0,0 @@
|
|
|
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 { DOMUtilities } from 'treb-base-types';
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* support for resizable node, drag handle, drag rect, mask
|
|
26
|
-
* FIXME: make this composable (decorator?)
|
|
27
|
-
* FIXME: make this generic, we can use it for some other stuff (charts?)
|
|
28
|
-
*/
|
|
29
|
-
export class Resizable {
|
|
30
|
-
|
|
31
|
-
private static resize_mask: HTMLElement;
|
|
32
|
-
private static resize_rect: HTMLElement;
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* adding layout_reference to move the handle. to keep this backwards
|
|
36
|
-
* compatible, we add it as a last, optional parameter. at some point
|
|
37
|
-
* we can create a replacement class and migrate.
|
|
38
|
-
*
|
|
39
|
-
* this is a weird pattern, we don't need an instance of this class...
|
|
40
|
-
* goint to refactor
|
|
41
|
-
*
|
|
42
|
-
*/
|
|
43
|
-
constructor(container: HTMLElement, node: HTMLElement, resize_callback: () => void,
|
|
44
|
-
layout_reference: HTMLElement = container) {
|
|
45
|
-
|
|
46
|
-
Resizable.Create({
|
|
47
|
-
container,
|
|
48
|
-
node,
|
|
49
|
-
resize_callback,
|
|
50
|
-
layout_reference});
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
public static Create(options: {
|
|
55
|
-
container: HTMLElement;
|
|
56
|
-
node: HTMLElement;
|
|
57
|
-
resize_callback?: () => void;
|
|
58
|
-
layout_reference?: HTMLElement;
|
|
59
|
-
}): void {
|
|
60
|
-
|
|
61
|
-
const resize_handle = DOMUtilities.Div('treb-embed-resize-handle');
|
|
62
|
-
|
|
63
|
-
(options.layout_reference || options.container).appendChild(resize_handle);
|
|
64
|
-
|
|
65
|
-
if (!Resizable.resize_mask) {
|
|
66
|
-
let mask = document.querySelector('.treb-embed-mouse-mask');
|
|
67
|
-
if (!mask) {
|
|
68
|
-
mask = DOMUtilities.Div('treb-embed-mouse-mask');
|
|
69
|
-
document.body.appendChild(mask);
|
|
70
|
-
}
|
|
71
|
-
Resizable.resize_mask = mask as HTMLElement;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if (!Resizable.resize_rect) {
|
|
75
|
-
let rect = document.querySelector('.treb-embed-resize-rect');
|
|
76
|
-
if (!rect) {
|
|
77
|
-
rect = DOMUtilities.Div('treb-embed-resize-rect');
|
|
78
|
-
Resizable.resize_mask.appendChild(rect);
|
|
79
|
-
}
|
|
80
|
-
Resizable.resize_rect = rect as HTMLElement;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// eslint-disable-next-line prefer-const
|
|
84
|
-
let mouseup: () => void;
|
|
85
|
-
|
|
86
|
-
// eslint-disable-next-line prefer-const
|
|
87
|
-
let mousemove: (event: MouseEvent) => void;
|
|
88
|
-
|
|
89
|
-
let container_rect = { width: 0, height: 0 };
|
|
90
|
-
let offset = { x: 0, y: 0 };
|
|
91
|
-
let delta = { x: 0, y: 0 };
|
|
92
|
-
|
|
93
|
-
const cleanup = () => {
|
|
94
|
-
|
|
95
|
-
Resizable.resize_mask.removeEventListener('mousemove', mousemove);
|
|
96
|
-
Resizable.resize_mask.removeEventListener('mouseup', mouseup);
|
|
97
|
-
Resizable.resize_mask.style.display = 'none';
|
|
98
|
-
|
|
99
|
-
if (delta.x || delta.y) {
|
|
100
|
-
const bounding_rect = options.container.getBoundingClientRect();
|
|
101
|
-
const width = bounding_rect.width + delta.x;
|
|
102
|
-
const height = bounding_rect.height + delta.y;
|
|
103
|
-
options.container.style.width = `${width}px`;
|
|
104
|
-
options.container.style.height = `${height}px`;
|
|
105
|
-
if (options.resize_callback) {
|
|
106
|
-
options.resize_callback();
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
mousemove = (event: MouseEvent) => {
|
|
113
|
-
|
|
114
|
-
if (!event.buttons) {
|
|
115
|
-
cleanup();
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
if (delta.x !== event.clientX - offset.x) {
|
|
120
|
-
delta.x = event.clientX - offset.x;
|
|
121
|
-
Resizable.resize_rect.style.width = `${container_rect.width + delta.x + 4}px`;
|
|
122
|
-
}
|
|
123
|
-
if (delta.y !== event.clientY - offset.y) {
|
|
124
|
-
delta.y = event.clientY - offset.y;
|
|
125
|
-
Resizable.resize_rect.style.height = `${container_rect.height + delta.y + 4}px`;
|
|
126
|
-
}
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
mouseup = () => {
|
|
130
|
-
cleanup();
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
resize_handle.addEventListener('mousedown', (event) => {
|
|
134
|
-
|
|
135
|
-
event.stopPropagation();
|
|
136
|
-
event.preventDefault();
|
|
137
|
-
|
|
138
|
-
const bounding_rect = options.node.getBoundingClientRect();
|
|
139
|
-
container_rect = { width: bounding_rect.width, height: bounding_rect.height };
|
|
140
|
-
|
|
141
|
-
if (Resizable.resize_rect) {
|
|
142
|
-
Resizable.resize_rect.style.top = `${bounding_rect.top - 2}px`;
|
|
143
|
-
Resizable.resize_rect.style.left = `${bounding_rect.left - 2}px`;
|
|
144
|
-
Resizable.resize_rect.style.width = `${bounding_rect.width + 4}px`;
|
|
145
|
-
Resizable.resize_rect.style.height = `${bounding_rect.height + 4}px`;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
offset = { x: event.clientX, y: event.clientY };
|
|
149
|
-
delta = { x: 0, y: 0 };
|
|
150
|
-
|
|
151
|
-
Resizable.resize_mask.style.display = 'block';
|
|
152
|
-
Resizable.resize_mask.addEventListener('mousemove', mousemove);
|
|
153
|
-
Resizable.resize_mask.addEventListener('mouseup', mouseup);
|
|
154
|
-
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
}
|