@trebco/treb 27.12.2 → 28.2.0
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 +13 -11
- package/dist/treb.d.ts +33 -5
- package/esbuild-custom-element.mjs +3 -1
- package/package.json +8 -6
- package/treb-base-types/src/dom-utilities.ts +157 -19
- package/treb-base-types/src/import.ts +1 -0
- 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 +153 -140
- 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-export/src/export-worker/export-worker.ts +7 -12
- package/treb-export/src/export2.ts +57 -33
- package/treb-export/src/import2.ts +61 -21
- package/treb-export/src/workbook2.ts +69 -24
- package/treb-export/src/zip-wrapper.ts +96 -0
- 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 +1 -1
- 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/annotation.ts +2 -2
- 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
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
*
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
import {
|
|
22
|
+
import { DOMContext } from 'treb-base-types';
|
|
23
23
|
import type { DataModel, ViewModel } from '../types/data_model';
|
|
24
24
|
|
|
25
25
|
import type { Tile } from '../types/tile';
|
|
@@ -185,12 +185,16 @@ export abstract class BaseLayout {
|
|
|
185
185
|
private initialized = false;
|
|
186
186
|
|
|
187
187
|
|
|
188
|
-
constructor(protected model: DataModel, protected view: ViewModel, mock = false) {
|
|
188
|
+
constructor(protected model: DataModel, protected view: ViewModel, mock = false, public DOM = DOMContext.GetInstance()) {
|
|
189
189
|
|
|
190
190
|
if (mock) {
|
|
191
191
|
return;
|
|
192
192
|
}
|
|
193
193
|
|
|
194
|
+
if (!DOM) {
|
|
195
|
+
throw new Error('missing DOM context');
|
|
196
|
+
}
|
|
197
|
+
|
|
194
198
|
this.dpr = Math.max(1, self.devicePixelRatio || 1);
|
|
195
199
|
|
|
196
200
|
// now attaching to node... no longer global
|
|
@@ -201,16 +205,14 @@ export abstract class BaseLayout {
|
|
|
201
205
|
// contexts; the mask will be under the next sheet. so either
|
|
202
206
|
// global in body, or instance local.
|
|
203
207
|
|
|
204
|
-
this.mask =
|
|
205
|
-
this.tooltip =
|
|
208
|
+
this.mask = DOM.Div('treb-mouse-mask');
|
|
209
|
+
this.tooltip = DOM.Div('treb-tooltip');
|
|
206
210
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
this.dropdown_caret = DOMUtilities.SVG('svg', 'treb-dropdown-caret');
|
|
211
|
+
this.dropdown_caret = DOM.SVG('svg', 'treb-dropdown-caret');
|
|
210
212
|
this.dropdown_caret.setAttribute('viewBox', '0 0 24 24');
|
|
211
213
|
this.dropdown_caret.tabIndex = -1;
|
|
212
214
|
|
|
213
|
-
const caret =
|
|
215
|
+
const caret = DOM.SVG('path');
|
|
214
216
|
caret.setAttribute('d', 'M5,7 L12,17 L19,7');
|
|
215
217
|
this.dropdown_caret.appendChild(caret);
|
|
216
218
|
|
|
@@ -247,8 +249,10 @@ export abstract class BaseLayout {
|
|
|
247
249
|
});
|
|
248
250
|
*/
|
|
249
251
|
|
|
250
|
-
this.dropdown_list =
|
|
251
|
-
|
|
252
|
+
this.dropdown_list = DOM.Div('treb-dropdown-list', undefined, {
|
|
253
|
+
attrs: { tabindex: '-1' },
|
|
254
|
+
});
|
|
255
|
+
// this.dropdown_list.setAttribute('tabindex', '-1'); // focusable
|
|
252
256
|
|
|
253
257
|
// this.dropdown_caret.addEventListener('keydown', (event) => {
|
|
254
258
|
this.dropdown_list.addEventListener('keydown', (event) => {
|
|
@@ -346,15 +350,17 @@ export abstract class BaseLayout {
|
|
|
346
350
|
this.dropdown_selected = target as HTMLElement;
|
|
347
351
|
});
|
|
348
352
|
|
|
349
|
-
this.mock_selection =
|
|
350
|
-
|
|
353
|
+
this.mock_selection = DOM.Div('mock-selection-node', undefined, {
|
|
354
|
+
html: ' ',
|
|
355
|
+
});
|
|
356
|
+
// this.mock_selection.innerHTML = ' ';
|
|
351
357
|
|
|
352
|
-
this.note_node =
|
|
353
|
-
this.title_node =
|
|
358
|
+
this.note_node = DOM.Div('treb-note');
|
|
359
|
+
this.title_node = DOM.Div('treb-hover-title');
|
|
354
360
|
|
|
355
|
-
this.sort_button =
|
|
361
|
+
this.sort_button = DOM.Create(
|
|
356
362
|
'button',
|
|
357
|
-
'treb-sort-button', undefined,
|
|
363
|
+
'treb-sort-button', undefined, { attrs: { title: 'Sort table', tabindex: '-1' }});
|
|
358
364
|
|
|
359
365
|
this.HideNote();
|
|
360
366
|
|
|
@@ -1167,15 +1173,18 @@ export abstract class BaseLayout {
|
|
|
1167
1173
|
|
|
1168
1174
|
// FIXME: limit to edge (causing problems in chrome? ...)
|
|
1169
1175
|
|
|
1170
|
-
|
|
1176
|
+
if (this.DOM.doc) {
|
|
1177
|
+
|
|
1178
|
+
const selection = this.DOM.GetSelection();
|
|
1171
1179
|
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1180
|
+
if (selection) {
|
|
1181
|
+
const range = this.DOM.doc.createRange();
|
|
1182
|
+
range.selectNodeContents(this.mock_selection);
|
|
1183
|
+
selection.removeAllRanges();
|
|
1184
|
+
selection.addRange(range);
|
|
1185
|
+
|
|
1186
|
+
}
|
|
1177
1187
|
|
|
1178
|
-
// selection.collapseToEnd();
|
|
1179
1188
|
}
|
|
1180
1189
|
|
|
1181
1190
|
}
|
|
@@ -1194,7 +1203,7 @@ export abstract class BaseLayout {
|
|
|
1194
1203
|
parent: HTMLElement,
|
|
1195
1204
|
mark_dirty = true): Tile {
|
|
1196
1205
|
|
|
1197
|
-
const tile =
|
|
1206
|
+
const tile = this.DOM.Create('canvas') as Tile;
|
|
1198
1207
|
tile.setAttribute('class', classes);
|
|
1199
1208
|
tile.logical_size = size;
|
|
1200
1209
|
tile.width = size.width * this.dpr;
|
|
@@ -1403,7 +1412,7 @@ export abstract class BaseLayout {
|
|
|
1403
1412
|
|
|
1404
1413
|
this.dropdown_list.textContent = '';
|
|
1405
1414
|
for (const value of list) {
|
|
1406
|
-
const entry =
|
|
1415
|
+
const entry = this.DOM.Div(undefined, this.dropdown_list);
|
|
1407
1416
|
if (current === value) {
|
|
1408
1417
|
this.dropdown_selected = entry;
|
|
1409
1418
|
entry.classList.add('selected');
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
|
|
22
22
|
import { BaseLayout } from './base_layout';
|
|
23
23
|
import type { Tile } from '../types/tile';
|
|
24
|
-
import {
|
|
24
|
+
import { DOMContext } from 'treb-base-types';
|
|
25
25
|
import type { DataModel, ViewModel } from '../types/data_model';
|
|
26
26
|
|
|
27
27
|
|
|
@@ -32,8 +32,8 @@ import type { DataModel, ViewModel } from '../types/data_model';
|
|
|
32
32
|
*/
|
|
33
33
|
export class GridLayout extends BaseLayout {
|
|
34
34
|
|
|
35
|
-
constructor(model: DataModel, view: ViewModel){
|
|
36
|
-
super(model, view);
|
|
35
|
+
constructor(model: DataModel, view: ViewModel, DOM: DOMContext){
|
|
36
|
+
super(model, view, false, DOM);
|
|
37
37
|
|
|
38
38
|
// nodes always exist
|
|
39
39
|
|
|
@@ -41,37 +41,37 @@ export class GridLayout extends BaseLayout {
|
|
|
41
41
|
// mask needs to get attached to a container, when it's
|
|
42
42
|
// available
|
|
43
43
|
|
|
44
|
-
this.column_header =
|
|
45
|
-
this.row_header =
|
|
44
|
+
this.column_header = DOM.Div('treb-top-header');
|
|
45
|
+
this.row_header = DOM.Div('treb-left-header');
|
|
46
46
|
|
|
47
|
-
this.corner =
|
|
48
|
-
this.corner_canvas =
|
|
47
|
+
this.corner = DOM.Div('treb-corner');
|
|
48
|
+
this.corner_canvas = DOM.Create('canvas');
|
|
49
49
|
this.corner.appendChild(this.corner_canvas);
|
|
50
50
|
|
|
51
|
-
this.contents =
|
|
52
|
-
this.buffer_canvas =
|
|
51
|
+
this.contents = DOM.Div('treb-contents');
|
|
52
|
+
this.buffer_canvas = DOM.Create('canvas', 'treb-buffer-canvas', this.contents);
|
|
53
53
|
|
|
54
54
|
// selection node attached to contents
|
|
55
|
-
this.grid_selection =
|
|
55
|
+
this.grid_selection = DOM.SVG('svg', 'treb-grid-selection', this.contents);
|
|
56
56
|
|
|
57
57
|
// selection node for frozen rows
|
|
58
|
-
this.row_header_selection =
|
|
59
|
-
this.row_header_annotations =
|
|
58
|
+
this.row_header_selection = DOM.SVG('svg', ['frozen-selection', 'frozen-selection-rows'], this.column_header);
|
|
59
|
+
this.row_header_annotations = DOM.Div('frozen-annotation-container frozen-annotation-container-rows', this.column_header);
|
|
60
60
|
|
|
61
61
|
// ...columns
|
|
62
|
-
this.column_header_selection =
|
|
63
|
-
this.column_header_annotations =
|
|
62
|
+
this.column_header_selection = DOM.SVG('svg', ['frozen-selection', 'frozen-selection-columns'], this.row_header);
|
|
63
|
+
this.column_header_annotations = DOM.Div('frozen-annotation-container frozen-annotation-container-columns', this.row_header);
|
|
64
64
|
|
|
65
65
|
// ...corner
|
|
66
|
-
this.corner_selection =
|
|
67
|
-
this.corner_annotations =
|
|
66
|
+
this.corner_selection = DOM.SVG('svg', 'frozen-selection', this.corner);
|
|
67
|
+
this.corner_annotations = DOM.Div('frozen-annotation-container frozen-annotation-container-corner', this.corner);
|
|
68
68
|
|
|
69
69
|
|
|
70
|
-
this.annotation_container =
|
|
70
|
+
this.annotation_container = DOM.Div('treb-annotation-container');
|
|
71
71
|
|
|
72
|
-
this.grid_cover =
|
|
73
|
-
this.column_header_cover =
|
|
74
|
-
this.row_header_cover =
|
|
72
|
+
this.grid_cover = DOM.Div('tile-cover grid-cover');
|
|
73
|
+
this.column_header_cover = DOM.Div('tile-cover column-header-cover');
|
|
74
|
+
this.row_header_cover = DOM.Div('tile-cover row-header-cover');
|
|
75
75
|
|
|
76
76
|
}
|
|
77
77
|
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
import type { Theme, ICellAddress } from 'treb-base-types';
|
|
23
|
-
import {
|
|
23
|
+
import { DOMContext, Rectangle } from 'treb-base-types';
|
|
24
24
|
import type { BaseLayout } from '../layout/base_layout';
|
|
25
25
|
import type { SelectionOffset } from './svg_selection_block';
|
|
26
26
|
import { SVGSelectionBlock } from './svg_selection_block';
|
|
@@ -289,7 +289,7 @@ export class SelectionRenderer {
|
|
|
289
289
|
|
|
290
290
|
let selection_block: SVGSelectionBlock = node_set[index];
|
|
291
291
|
if (!selection_block) {
|
|
292
|
-
selection_block = new SVGSelectionBlock(!index, this.theme);
|
|
292
|
+
selection_block = new SVGSelectionBlock(!index, this.theme, undefined, node);
|
|
293
293
|
node_set[index] = selection_block;
|
|
294
294
|
|
|
295
295
|
if (index) {
|
|
@@ -302,7 +302,7 @@ export class SelectionRenderer {
|
|
|
302
302
|
|
|
303
303
|
let group: SVGElement = node.querySelector('.alternate-selections') as SVGElement;
|
|
304
304
|
if (!group) {
|
|
305
|
-
group =
|
|
305
|
+
group = this.layout.DOM.SVG('g', 'alternate-selections');
|
|
306
306
|
node.appendChild(group);
|
|
307
307
|
}
|
|
308
308
|
group?.appendChild(selection_block.g);
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
*
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
import {
|
|
22
|
+
import { DOMContext, type Theme } from 'treb-base-types';
|
|
23
23
|
|
|
24
24
|
export enum Orientation {
|
|
25
25
|
Horizontal,
|
|
@@ -37,9 +37,11 @@ export class HeaderOverlay {
|
|
|
37
37
|
private container: SVGElement,
|
|
38
38
|
private orientation: Orientation) {
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
this.
|
|
40
|
+
const DOM = DOMContext.GetInstance(container.ownerDocument);
|
|
41
|
+
|
|
42
|
+
this.g = DOM.SVG('g', 'treb-header-overlay');
|
|
43
|
+
this.overlay = DOM.SVG('rect', 'treb-overlay');
|
|
44
|
+
this.highlight = DOM.SVG('rect', 'treb-highlight');
|
|
43
45
|
|
|
44
46
|
this.g.style.display = 'none';
|
|
45
47
|
this.g.appendChild(this.highlight);
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
*
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
import { type Theme, type Rectangle,
|
|
22
|
+
import { type Theme, type Rectangle, DOMContext } from 'treb-base-types';
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* the original selections -- a canvas overlaid over the tile canvases --
|
|
@@ -44,12 +44,15 @@ export class SVGSelectionBlock {
|
|
|
44
44
|
|
|
45
45
|
constructor( primary: boolean,
|
|
46
46
|
private theme: Theme,
|
|
47
|
-
private offset: SelectionOffset = {x: 0, y: 0}
|
|
47
|
+
private offset: SelectionOffset = {x: 0, y: 0},
|
|
48
|
+
node: SVGElement) {
|
|
48
49
|
|
|
49
|
-
|
|
50
|
+
const DOM = DOMContext.GetInstance(node.ownerDocument);
|
|
51
|
+
|
|
52
|
+
this.g = DOM.SVG('g');
|
|
50
53
|
this.g.setAttribute('transform', `translate(${offset.x}, ${offset.y})`);
|
|
51
54
|
|
|
52
|
-
this.outline =
|
|
55
|
+
this.outline = DOM.SVG('rect', 'outline');
|
|
53
56
|
|
|
54
57
|
if (primary) {
|
|
55
58
|
|
|
@@ -58,8 +61,8 @@ export class SVGSelectionBlock {
|
|
|
58
61
|
// primary selections have a separate fill, plus the nub. separate
|
|
59
62
|
// fill because the "target" is unfilled.
|
|
60
63
|
|
|
61
|
-
this.fill =
|
|
62
|
-
this.nub =
|
|
64
|
+
this.fill = DOM.SVG('path', 'fill');
|
|
65
|
+
this.nub = DOM.SVG('rect', 'nub');
|
|
63
66
|
|
|
64
67
|
this.g.appendChild(this.fill);
|
|
65
68
|
this.g.appendChild(this.outline);
|
|
@@ -75,7 +78,7 @@ export class SVGSelectionBlock {
|
|
|
75
78
|
// and use currentColor, but we can't set opacity separately so we
|
|
76
79
|
// need another node. which is a waste, but ergonomics ftw!
|
|
77
80
|
|
|
78
|
-
this.fill =
|
|
81
|
+
this.fill = DOM.SVG('rect', 'fill');
|
|
79
82
|
|
|
80
83
|
// this.SetThemeColor(0);
|
|
81
84
|
// if (theme.additional_selection_line_dash_array) {
|
|
@@ -58,7 +58,7 @@ import {
|
|
|
58
58
|
MDParser,
|
|
59
59
|
} from 'treb-parser';
|
|
60
60
|
|
|
61
|
-
import {
|
|
61
|
+
import { SerializeHTML } from 'treb-utils';
|
|
62
62
|
import type { ParseResult as ParseResult2 } from 'treb-format';
|
|
63
63
|
import { NumberFormatCache, LotusDate, ValueParser, type Hints, NumberFormat } from 'treb-format';
|
|
64
64
|
import { SelectionRenderer } from '../render/selection-renderer';
|
|
@@ -111,7 +111,7 @@ import { CommandKey
|
|
|
111
111
|
|
|
112
112
|
import type { DataModel, SerializedModel } from './data_model';
|
|
113
113
|
|
|
114
|
-
import {
|
|
114
|
+
import { DOMContext } from 'treb-base-types';
|
|
115
115
|
import { GridBase } from './grid_base';
|
|
116
116
|
import type { SetRangeOptions } from './set_range_options';
|
|
117
117
|
import type { ClipboardCellData } from './clipboard_data';
|
|
@@ -360,6 +360,8 @@ export class Grid extends GridBase {
|
|
|
360
360
|
|
|
361
361
|
private tab_bar?: TabBar;
|
|
362
362
|
|
|
363
|
+
private DOM = DOMContext.GetInstance();
|
|
364
|
+
|
|
363
365
|
// --- constructor -----------------------------------------------------------
|
|
364
366
|
|
|
365
367
|
/**
|
|
@@ -369,7 +371,8 @@ export class Grid extends GridBase {
|
|
|
369
371
|
options: GridOptions = {},
|
|
370
372
|
model: DataModel,
|
|
371
373
|
theme: Theme = DefaultTheme,
|
|
372
|
-
initialze_dom = true
|
|
374
|
+
initialze_dom = true,
|
|
375
|
+
DOM: DOMContext ) {
|
|
373
376
|
|
|
374
377
|
super(options, model);
|
|
375
378
|
|
|
@@ -385,7 +388,8 @@ export class Grid extends GridBase {
|
|
|
385
388
|
return;
|
|
386
389
|
}
|
|
387
390
|
|
|
388
|
-
this.
|
|
391
|
+
this.DOM = DOM;
|
|
392
|
+
this.layout = new GridLayout(this.model, this.view, DOM);
|
|
389
393
|
|
|
390
394
|
if (options.initial_scale) {
|
|
391
395
|
if (typeof options.initial_scale === 'string') {
|
|
@@ -571,84 +575,83 @@ export class Grid extends GridBase {
|
|
|
571
575
|
|
|
572
576
|
// FIXME: why is this not in layout? it is layout.
|
|
573
577
|
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
const move_target = DOMUtilities.Div('annotation-move-target', view.node);
|
|
580
|
-
const resize_target = DOMUtilities.Div('annotation-resize-target', view.node);
|
|
581
|
-
|
|
582
|
-
if (view.node) {
|
|
583
|
-
const node = view.node;
|
|
584
|
-
|
|
585
|
-
// support focus
|
|
586
|
-
node.setAttribute('tabindex', '-1');
|
|
578
|
+
const node = this.DOM.Div('annotation', undefined, {
|
|
579
|
+
data: { scale: this.layout.scale.toString() },
|
|
580
|
+
style: { fontSize: `${10 * this.layout.scale}pt` },
|
|
581
|
+
attrs: { tabindex: '-1', },
|
|
582
|
+
events: {
|
|
587
583
|
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
if (event.button !== 0) {
|
|
591
|
-
return;
|
|
592
|
-
}
|
|
584
|
+
mousedown: (event) => {
|
|
593
585
|
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
// console.info('resolved', event);
|
|
597
|
-
if (event) {
|
|
598
|
-
this.grid_events.Publish(event);
|
|
586
|
+
if (event.button !== 0) {
|
|
587
|
+
return;
|
|
599
588
|
}
|
|
589
|
+
|
|
590
|
+
this.layout.AnnotationMouseDown(annotation, node, event, move_target, resize_target).then(event => {
|
|
591
|
+
// console.info('resolved', event);
|
|
592
|
+
if (event) {
|
|
593
|
+
this.grid_events.Publish(event);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
if (annotation.data.layout) {
|
|
597
|
+
this.EnsureAddress(annotation.data.layout.br.address, 1);
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
});
|
|
601
|
+
},
|
|
600
602
|
|
|
601
|
-
|
|
602
|
-
|
|
603
|
+
focusin: () => {
|
|
604
|
+
|
|
605
|
+
for (const element of this.layout.GetFrozenAnnotations(annotation)) {
|
|
606
|
+
element.classList.add('clone-focus');
|
|
603
607
|
}
|
|
608
|
+
|
|
609
|
+
this.selected_annotation = annotation;
|
|
610
|
+
this.primary_selection.empty = true; // FIXME: not using method? (...)
|
|
611
|
+
|
|
612
|
+
// this is done for the side-effect when we start editing, we
|
|
613
|
+
// capture the sheet of the primary selection. if you switch
|
|
614
|
+
// sheets while editing, the selection won't be set so it persists.
|
|
615
|
+
// we need that to switch back to the correct sheet when an edit ends.
|
|
616
|
+
|
|
617
|
+
this.primary_selection.target = { row: -1, column: -1, sheet_id: this.active_sheet.id };
|
|
618
|
+
this.HideGridSelection();
|
|
604
619
|
|
|
605
|
-
}
|
|
606
|
-
});
|
|
607
|
-
|
|
608
|
-
node.addEventListener('focusin', () => {
|
|
609
|
-
|
|
610
|
-
// console.info('annotation focusin', annotation);
|
|
611
|
-
|
|
612
|
-
for (const element of this.layout.GetFrozenAnnotations(annotation)) {
|
|
613
|
-
element.classList.add('clone-focus');
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
this.selected_annotation = annotation;
|
|
617
|
-
this.primary_selection.empty = true; // FIXME: not using method? (...)
|
|
620
|
+
},
|
|
618
621
|
|
|
619
|
-
|
|
620
|
-
// capture the sheet of the primary selection. if you switch
|
|
621
|
-
// sheets while editing, the selection won't be set so it persists.
|
|
622
|
-
// we need that to switch back to the correct sheet when an edit ends.
|
|
622
|
+
focusout: (event) => {
|
|
623
623
|
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
624
|
+
// console.info('annotation focusout', annotation);
|
|
625
|
+
|
|
626
|
+
for (const element of this.layout.GetFrozenAnnotations(annotation)) {
|
|
627
|
+
element.classList.remove('clone-focus');
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
if (this.formula_bar && this.formula_bar.IsElement((event as FocusEvent).relatedTarget as HTMLElement)) {
|
|
631
|
+
// console.info('editing...');
|
|
632
|
+
this.primary_selection.empty = true;
|
|
633
|
+
this.RenderSelections();
|
|
634
|
+
this.editing_annotation = annotation;
|
|
635
|
+
this.layout.ShowSelections(true);
|
|
636
|
+
}
|
|
637
|
+
else {
|
|
638
|
+
if (this.selected_annotation === annotation) {
|
|
639
|
+
this.selected_annotation = undefined;
|
|
640
|
+
}
|
|
641
|
+
this.ShowGridSelection();
|
|
642
|
+
}
|
|
643
|
+
},
|
|
627
644
|
|
|
628
|
-
|
|
645
|
+
}
|
|
646
|
+
});
|
|
629
647
|
|
|
630
|
-
|
|
648
|
+
view.node = node;
|
|
631
649
|
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
if (this.formula_bar && this.formula_bar.IsElement((event as FocusEvent).relatedTarget as HTMLElement)) {
|
|
637
|
-
// console.info('editing...');
|
|
638
|
-
this.primary_selection.empty = true;
|
|
639
|
-
this.RenderSelections();
|
|
640
|
-
this.editing_annotation = annotation;
|
|
641
|
-
this.layout.ShowSelections(true);
|
|
642
|
-
}
|
|
643
|
-
else {
|
|
644
|
-
if (this.selected_annotation === annotation) {
|
|
645
|
-
this.selected_annotation = undefined;
|
|
646
|
-
}
|
|
647
|
-
this.ShowGridSelection();
|
|
648
|
-
}
|
|
649
|
-
});
|
|
650
|
+
view.content_node = this.DOM.Div('annotation-content', node);
|
|
651
|
+
const move_target = this.DOM.Div('annotation-move-target', node);
|
|
652
|
+
const resize_target = this.DOM.Div('annotation-resize-target', node);
|
|
650
653
|
|
|
651
|
-
|
|
654
|
+
node.addEventListener('keydown', (event) => {
|
|
652
655
|
|
|
653
656
|
const rect = annotation.scaled_rect;
|
|
654
657
|
if (!rect) {
|
|
@@ -748,14 +751,8 @@ export class Grid extends GridBase {
|
|
|
748
751
|
}
|
|
749
752
|
|
|
750
753
|
});
|
|
751
|
-
}
|
|
752
|
-
}
|
|
753
754
|
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
// if (annotation.class_name) {
|
|
757
|
-
// annotation.node.classList.add(annotation.class_name);
|
|
758
|
-
// }
|
|
755
|
+
}
|
|
759
756
|
|
|
760
757
|
if (add_to_layout) {
|
|
761
758
|
this.layout.AddAnnotation(annotation);
|
|
@@ -2413,7 +2410,7 @@ export class Grid extends GridBase {
|
|
|
2413
2410
|
*/
|
|
2414
2411
|
private ActivateSheetTasks() {
|
|
2415
2412
|
|
|
2416
|
-
this.active_sheet.Activate();
|
|
2413
|
+
this.active_sheet.Activate(this.DOM);
|
|
2417
2414
|
|
|
2418
2415
|
if (this.active_sheet.image && !this.active_sheet.image.complete) {
|
|
2419
2416
|
|
|
@@ -2785,7 +2782,7 @@ export class Grid extends GridBase {
|
|
|
2785
2782
|
|
|
2786
2783
|
if (!this.render_token) {
|
|
2787
2784
|
this.render_token = 1;
|
|
2788
|
-
|
|
2785
|
+
Promise.resolve().then(() => {
|
|
2789
2786
|
this.render_token = 0;
|
|
2790
2787
|
this.Repaint(force, full_tile);
|
|
2791
2788
|
});
|
|
@@ -3846,7 +3843,7 @@ export class Grid extends GridBase {
|
|
|
3846
3843
|
if (cell.hyperlink) {
|
|
3847
3844
|
if (this.PointInTextPart(address, offset_point, cell)) {
|
|
3848
3845
|
const link = cell.hyperlink;
|
|
3849
|
-
|
|
3846
|
+
Promise.resolve().then(() => {
|
|
3850
3847
|
this.grid_events.Publish({
|
|
3851
3848
|
type: 'cell-event',
|
|
3852
3849
|
data: {
|
|
@@ -4678,7 +4675,9 @@ export class Grid extends GridBase {
|
|
|
4678
4675
|
// console.info('ek', event.key);
|
|
4679
4676
|
|
|
4680
4677
|
if (!selection.empty) {
|
|
4681
|
-
|
|
4678
|
+
if (event.key !== 'Escape') {
|
|
4679
|
+
this.OverlayEditCell(selection, true, event);
|
|
4680
|
+
}
|
|
4682
4681
|
}
|
|
4683
4682
|
|
|
4684
4683
|
return;
|