@handsontable/angular-wrapper 0.0.0-next-c272dd6-20261013 → 0.0.0-next-a26137c-20261014
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/fesm2022/handsontable-angular-wrapper.mjs +1225 -1582
- package/fesm2022/handsontable-angular-wrapper.mjs.map +1 -1
- package/package.json +1 -1
- package/types/handsontable-angular-wrapper.d.ts +683 -0
- package/index.d.ts +0 -5
- package/lib/editor/base-editor-adapter.d.ts +0 -92
- package/lib/editor/custom-editor-placeholder.component.d.ts +0 -33
- package/lib/editor/editor-factory-adapter.d.ts +0 -13
- package/lib/editor/hot-cell-editor-advanced.component.d.ts +0 -42
- package/lib/editor/hot-cell-editor-base.directive.d.ts +0 -25
- package/lib/editor/hot-cell-editor.component.d.ts +0 -37
- package/lib/editor/models/factory-editor-properties.d.ts +0 -32
- package/lib/editor/models/keyboard-shortcut-config.d.ts +0 -13
- package/lib/hot-table.component.d.ts +0 -78
- package/lib/hot-table.module.d.ts +0 -8
- package/lib/models/column-settings.d.ts +0 -27
- package/lib/models/grid-settings.d.ts +0 -8
- package/lib/renderer/hot-cell-renderer-advanced.component.d.ts +0 -16
- package/lib/renderer/hot-cell-renderer-base.directive.d.ts +0 -23
- package/lib/renderer/hot-cell-renderer.component.d.ts +0 -17
- package/lib/renderer/hot-dynamic-renderer-component.service.d.ts +0 -183
- package/lib/services/hot-global-config.service.d.ts +0 -110
- package/lib/services/hot-settings-resolver.service.d.ts +0 -77
- package/public-api.d.ts +0 -12
|
@@ -1,50 +1,64 @@
|
|
|
1
|
-
import * as i0 from
|
|
2
|
-
import {
|
|
3
|
-
import { takeUntilDestroyed } from
|
|
4
|
-
import Handsontable from
|
|
5
|
-
import {
|
|
6
|
-
import { editorFactory } from
|
|
7
|
-
import { baseRenderer,
|
|
8
|
-
import { BehaviorSubject } from
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
1
|
+
import * as i0 from "@angular/core";
|
|
2
|
+
import { ChangeDetectionStrategy, Component, DestroyRef, Directive, ElementRef, EventEmitter, HostBinding, Inject, Injectable, InjectionToken, Input, NgModule, Output, ViewChild, ViewContainerRef, ViewEncapsulation, createComponent, inject } from "@angular/core";
|
|
3
|
+
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
|
4
|
+
import Handsontable from "handsontable/base";
|
|
5
|
+
import { skip, take } from "rxjs/operators";
|
|
6
|
+
import { editorFactory } from "handsontable/editors/factory";
|
|
7
|
+
import { baseRenderer, registerRenderer, rendererFactory } from "handsontable/renderers";
|
|
8
|
+
import { BehaviorSubject } from "rxjs";
|
|
9
|
+
var CustomEditorPlaceholderComponent = class CustomEditorPlaceholderComponent {
|
|
10
|
+
top;
|
|
11
|
+
left;
|
|
12
|
+
height;
|
|
13
|
+
width;
|
|
14
|
+
set isVisible(value) {
|
|
15
|
+
this._isVisible = value;
|
|
16
|
+
}
|
|
17
|
+
placeholderCustomClass = "handsontableInputHolder ht_clone_master";
|
|
18
|
+
set componentRef(hotEditorComponentRef) {
|
|
19
|
+
if (hotEditorComponentRef) this.container.insert(hotEditorComponentRef.hostView);
|
|
20
|
+
}
|
|
21
|
+
container;
|
|
22
|
+
get display() {
|
|
23
|
+
return this._isVisible ? "block" : "none";
|
|
24
|
+
}
|
|
25
|
+
_isVisible = false;
|
|
26
|
+
detachEditor() {
|
|
27
|
+
this.container.detach();
|
|
28
|
+
}
|
|
29
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
30
|
+
minVersion: "12.0.0",
|
|
31
|
+
version: "22.2.2",
|
|
32
|
+
ngImport: i0,
|
|
33
|
+
type: CustomEditorPlaceholderComponent,
|
|
34
|
+
deps: [],
|
|
35
|
+
target: i0.ɵɵFactoryTarget.Component
|
|
36
|
+
});
|
|
37
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
38
|
+
minVersion: "14.0.0",
|
|
39
|
+
version: "22.2.2",
|
|
40
|
+
type: CustomEditorPlaceholderComponent,
|
|
41
|
+
isStandalone: true,
|
|
42
|
+
selector: "ng-component",
|
|
43
|
+
inputs: {
|
|
44
|
+
top: "top",
|
|
45
|
+
left: "left",
|
|
46
|
+
height: "height",
|
|
47
|
+
width: "width",
|
|
48
|
+
isVisible: "isVisible",
|
|
49
|
+
placeholderCustomClass: "placeholderCustomClass",
|
|
50
|
+
componentRef: "componentRef"
|
|
51
|
+
},
|
|
52
|
+
viewQueries: [{
|
|
53
|
+
propertyName: "container",
|
|
54
|
+
first: true,
|
|
55
|
+
predicate: ["inputPlaceholder"],
|
|
56
|
+
descendants: true,
|
|
57
|
+
read: ViewContainerRef,
|
|
58
|
+
static: true
|
|
59
|
+
}],
|
|
60
|
+
ngImport: i0,
|
|
61
|
+
template: ` <div
|
|
48
62
|
[class]="placeholderCustomClass"
|
|
49
63
|
[style.display]="display"
|
|
50
64
|
[style.width.px]="width"
|
|
@@ -55,12 +69,20 @@ class CustomEditorPlaceholderComponent {
|
|
|
55
69
|
[style.left.px]="left"
|
|
56
70
|
>
|
|
57
71
|
<ng-template #inputPlaceholder></ng-template>
|
|
58
|
-
</div>`,
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
72
|
+
</div>`,
|
|
73
|
+
isInline: true,
|
|
74
|
+
changeDetection: i0.ChangeDetectionStrategy.OnPush
|
|
75
|
+
});
|
|
76
|
+
};
|
|
77
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
78
|
+
minVersion: "12.0.0",
|
|
79
|
+
version: "22.2.2",
|
|
80
|
+
ngImport: i0,
|
|
81
|
+
type: CustomEditorPlaceholderComponent,
|
|
82
|
+
decorators: [{
|
|
83
|
+
type: Component,
|
|
84
|
+
args: [{
|
|
85
|
+
template: ` <div
|
|
64
86
|
[class]="placeholderCustomClass"
|
|
65
87
|
[style.display]="display"
|
|
66
88
|
[style.width.px]="width"
|
|
@@ -72,1558 +94,1179 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImpo
|
|
|
72
94
|
>
|
|
73
95
|
<ng-template #inputPlaceholder></ng-template>
|
|
74
96
|
</div>`,
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
tabindex = -1;
|
|
413
|
-
/** The data-hot-input attribute for the editor. */
|
|
414
|
-
dataHotInput = '';
|
|
415
|
-
/** The handsontableInput class for the editor. */
|
|
416
|
-
handsontableInputClass = true;
|
|
417
|
-
/** Event triggered by Handsontable on closing the editor. */
|
|
418
|
-
onClose() { }
|
|
419
|
-
/** Event triggered by Handsontable on opening the editor. */
|
|
420
|
-
onOpen(event) { }
|
|
421
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: HotCellEditorComponent, deps: null, target: i0.ɵɵFactoryTarget.Directive });
|
|
422
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.25", type: HotCellEditorComponent, isStandalone: true, host: { properties: { "attr.tabindex": "this.tabindex", "attr.data-hot-input": "this.dataHotInput", "class.handsontableInput": "this.handsontableInputClass" } }, usesInheritance: true, ngImport: i0 });
|
|
423
|
-
}
|
|
424
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: HotCellEditorComponent, decorators: [{
|
|
425
|
-
type: Directive
|
|
426
|
-
}], propDecorators: { tabindex: [{
|
|
427
|
-
type: HostBinding,
|
|
428
|
-
args: ['attr.tabindex']
|
|
429
|
-
}], dataHotInput: [{
|
|
430
|
-
type: HostBinding,
|
|
431
|
-
args: ['attr.data-hot-input']
|
|
432
|
-
}], handsontableInputClass: [{
|
|
433
|
-
type: HostBinding,
|
|
434
|
-
args: ['class.handsontableInput']
|
|
435
|
-
}] } });
|
|
436
|
-
|
|
437
|
-
/**
|
|
438
|
-
* Factory function to create a custom Handsontable editor adapter for Angular components.
|
|
439
|
-
*
|
|
440
|
-
* This adapter integrates Angular components with Handsontable's editor system using the new
|
|
441
|
-
* editorFactory API, allowing you to use Angular components as custom cell editors while
|
|
442
|
-
* maintaining full Angular lifecycle management and change detection.
|
|
443
|
-
*
|
|
444
|
-
* @returns A custom editor class that can be used in Handsontable column settings.
|
|
445
|
-
*
|
|
446
|
-
*/
|
|
97
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
98
|
+
standalone: true
|
|
99
|
+
}]
|
|
100
|
+
}],
|
|
101
|
+
propDecorators: {
|
|
102
|
+
top: [{ type: Input }],
|
|
103
|
+
left: [{ type: Input }],
|
|
104
|
+
height: [{ type: Input }],
|
|
105
|
+
width: [{ type: Input }],
|
|
106
|
+
isVisible: [{ type: Input }],
|
|
107
|
+
placeholderCustomClass: [{ type: Input }],
|
|
108
|
+
componentRef: [{ type: Input }],
|
|
109
|
+
container: [{
|
|
110
|
+
type: ViewChild,
|
|
111
|
+
args: ["inputPlaceholder", {
|
|
112
|
+
read: ViewContainerRef,
|
|
113
|
+
static: true
|
|
114
|
+
}]
|
|
115
|
+
}]
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
var BaseEditorAdapter = class extends Handsontable.editors.BaseEditor {
|
|
119
|
+
_componentRef;
|
|
120
|
+
_editorPlaceHolderRef;
|
|
121
|
+
_isPlaceholderReady = false;
|
|
122
|
+
_finishEditSubscription;
|
|
123
|
+
_cancelEditSubscription;
|
|
124
|
+
constructor(instance) {
|
|
125
|
+
super(instance);
|
|
126
|
+
this.hot.addHook("afterRowResize", this.onAfterRowResize.bind(this));
|
|
127
|
+
this.hot.addHook("afterColumnResize", this.onAfterColumnResize.bind(this));
|
|
128
|
+
this.hot.addHook("afterDestroy", this.onAfterDestroy.bind(this));
|
|
129
|
+
}
|
|
130
|
+
prepare(row, column, prop, TD, originalValue, cellProperties) {
|
|
131
|
+
if (!this.isOpened()) {
|
|
132
|
+
super.prepare(row, column, prop, TD, originalValue, cellProperties);
|
|
133
|
+
const columnMeta = this.hot.getColumnMeta(column);
|
|
134
|
+
if (!this._isPlaceholderReady) {
|
|
135
|
+
this.createEditorPlaceholder(columnMeta._environmentInjector);
|
|
136
|
+
this._isPlaceholderReady = true;
|
|
137
|
+
}
|
|
138
|
+
this._componentRef = columnMeta._editorComponentReference;
|
|
139
|
+
this.cleanupSubscriptions();
|
|
140
|
+
this._finishEditSubscription = this._componentRef.instance.finishEdit.pipe(take(1)).subscribe(() => {
|
|
141
|
+
this.finishEditing();
|
|
142
|
+
});
|
|
143
|
+
this._cancelEditSubscription = this._componentRef.instance.cancelEdit.pipe(take(1)).subscribe(() => {
|
|
144
|
+
this.cancelChanges();
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
close() {
|
|
149
|
+
if (this.isOpened()) {
|
|
150
|
+
this.resetEditorState();
|
|
151
|
+
this._editorPlaceHolderRef?.changeDetectorRef.detectChanges();
|
|
152
|
+
this._editorPlaceHolderRef?.instance.detachEditor();
|
|
153
|
+
this._componentRef?.instance.onClose();
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
focus() {
|
|
157
|
+
this._componentRef?.instance.onFocus();
|
|
158
|
+
}
|
|
159
|
+
getValue() {
|
|
160
|
+
return this._componentRef?.instance?.getValue();
|
|
161
|
+
}
|
|
162
|
+
open(event) {
|
|
163
|
+
this.hot.getShortcutManager().setActiveContextName("editor");
|
|
164
|
+
this.applyPropsToEditor();
|
|
165
|
+
this._componentRef?.instance.onOpen(event);
|
|
166
|
+
}
|
|
167
|
+
setValue(newValue) {
|
|
168
|
+
this._componentRef?.instance?.setValue(newValue);
|
|
169
|
+
this._componentRef?.changeDetectorRef.detectChanges();
|
|
170
|
+
}
|
|
171
|
+
applyPropsToEditor() {
|
|
172
|
+
if (!this._componentRef || !this._editorPlaceHolderRef) return;
|
|
173
|
+
const rect = this.getEditedCellRect();
|
|
174
|
+
if (!this.isInFullEditMode()) this._componentRef.instance.setValue(null);
|
|
175
|
+
this._componentRef.setInput("originalValue", this.originalValue);
|
|
176
|
+
this._componentRef.setInput("row", this.row);
|
|
177
|
+
this._componentRef.setInput("column", this.col);
|
|
178
|
+
this._componentRef.setInput("prop", this.prop);
|
|
179
|
+
this._componentRef.setInput("cellProperties", this.cellProperties);
|
|
180
|
+
this._editorPlaceHolderRef.setInput("top", rect.top);
|
|
181
|
+
this._editorPlaceHolderRef.setInput("left", rect.start);
|
|
182
|
+
this._editorPlaceHolderRef.setInput("height", rect.height);
|
|
183
|
+
this._editorPlaceHolderRef.setInput("width", rect.width);
|
|
184
|
+
this._editorPlaceHolderRef.setInput("isVisible", true);
|
|
185
|
+
this._editorPlaceHolderRef.setInput("componentRef", this._componentRef);
|
|
186
|
+
this._editorPlaceHolderRef.changeDetectorRef.detectChanges();
|
|
187
|
+
}
|
|
188
|
+
createEditorPlaceholder(injector) {
|
|
189
|
+
this._editorPlaceHolderRef = createComponent(CustomEditorPlaceholderComponent, { environmentInjector: injector });
|
|
190
|
+
this.hot.rootElement.appendChild(this._editorPlaceHolderRef.location.nativeElement);
|
|
191
|
+
}
|
|
192
|
+
onAfterColumnResize() {
|
|
193
|
+
if (this.isOpened()) this.applyPropsToEditor();
|
|
194
|
+
}
|
|
195
|
+
onAfterRowResize() {
|
|
196
|
+
if (this.isOpened()) this.applyPropsToEditor();
|
|
197
|
+
}
|
|
198
|
+
onAfterDestroy() {
|
|
199
|
+
this.cleanupSubscriptions();
|
|
200
|
+
this._editorPlaceHolderRef?.destroy();
|
|
201
|
+
}
|
|
202
|
+
cleanupSubscriptions() {
|
|
203
|
+
if (this._finishEditSubscription) {
|
|
204
|
+
this._finishEditSubscription.unsubscribe();
|
|
205
|
+
this._finishEditSubscription = void 0;
|
|
206
|
+
}
|
|
207
|
+
if (this._cancelEditSubscription) {
|
|
208
|
+
this._cancelEditSubscription.unsubscribe();
|
|
209
|
+
this._cancelEditSubscription = void 0;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
resetEditorState() {
|
|
213
|
+
if (!this._editorPlaceHolderRef) return;
|
|
214
|
+
this._editorPlaceHolderRef.setInput("top", void 0);
|
|
215
|
+
this._editorPlaceHolderRef.setInput("left", void 0);
|
|
216
|
+
this._editorPlaceHolderRef.setInput("height", void 0);
|
|
217
|
+
this._editorPlaceHolderRef.setInput("width", void 0);
|
|
218
|
+
this._editorPlaceHolderRef.setInput("isVisible", false);
|
|
219
|
+
this._editorPlaceHolderRef.setInput("componentRef", void 0);
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
var HotCellRendererBase = class HotCellRendererBase {
|
|
223
|
+
value = "";
|
|
224
|
+
instance;
|
|
225
|
+
td;
|
|
226
|
+
row;
|
|
227
|
+
col;
|
|
228
|
+
prop;
|
|
229
|
+
cellProperties;
|
|
230
|
+
getProps() {
|
|
231
|
+
return this.cellProperties?.rendererProps ?? {};
|
|
232
|
+
}
|
|
233
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
234
|
+
minVersion: "12.0.0",
|
|
235
|
+
version: "22.2.2",
|
|
236
|
+
ngImport: i0,
|
|
237
|
+
type: HotCellRendererBase,
|
|
238
|
+
deps: [],
|
|
239
|
+
target: i0.ɵɵFactoryTarget.Directive
|
|
240
|
+
});
|
|
241
|
+
static ɵdir = i0.ɵɵngDeclareDirective({
|
|
242
|
+
minVersion: "14.0.0",
|
|
243
|
+
version: "22.2.2",
|
|
244
|
+
type: HotCellRendererBase,
|
|
245
|
+
isStandalone: true,
|
|
246
|
+
inputs: {
|
|
247
|
+
value: "value",
|
|
248
|
+
instance: "instance",
|
|
249
|
+
td: "td",
|
|
250
|
+
row: "row",
|
|
251
|
+
col: "col",
|
|
252
|
+
prop: "prop",
|
|
253
|
+
cellProperties: "cellProperties"
|
|
254
|
+
},
|
|
255
|
+
ngImport: i0
|
|
256
|
+
});
|
|
257
|
+
};
|
|
258
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
259
|
+
minVersion: "12.0.0",
|
|
260
|
+
version: "22.2.2",
|
|
261
|
+
ngImport: i0,
|
|
262
|
+
type: HotCellRendererBase,
|
|
263
|
+
decorators: [{ type: Directive }],
|
|
264
|
+
propDecorators: {
|
|
265
|
+
value: [{ type: Input }],
|
|
266
|
+
instance: [{ type: Input }],
|
|
267
|
+
td: [{ type: Input }],
|
|
268
|
+
row: [{ type: Input }],
|
|
269
|
+
col: [{ type: Input }],
|
|
270
|
+
prop: [{ type: Input }],
|
|
271
|
+
cellProperties: [{ type: Input }]
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
var HotCellRendererComponent = class HotCellRendererComponent extends HotCellRendererBase {
|
|
275
|
+
static RENDERER_MARKER = Symbol("HotCellRendererComponent");
|
|
276
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
277
|
+
minVersion: "12.0.0",
|
|
278
|
+
version: "22.2.2",
|
|
279
|
+
ngImport: i0,
|
|
280
|
+
type: HotCellRendererComponent,
|
|
281
|
+
deps: null,
|
|
282
|
+
target: i0.ɵɵFactoryTarget.Component
|
|
283
|
+
});
|
|
284
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
285
|
+
minVersion: "14.0.0",
|
|
286
|
+
version: "22.2.2",
|
|
287
|
+
type: HotCellRendererComponent,
|
|
288
|
+
isStandalone: true,
|
|
289
|
+
selector: "hot-cell-renderer",
|
|
290
|
+
usesInheritance: true,
|
|
291
|
+
ngImport: i0,
|
|
292
|
+
template: `<!-- This is an abstract component. Extend this component and provide your own template. -->`,
|
|
293
|
+
isInline: true,
|
|
294
|
+
changeDetection: i0.ChangeDetectionStrategy.OnPush
|
|
295
|
+
});
|
|
296
|
+
};
|
|
297
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
298
|
+
minVersion: "12.0.0",
|
|
299
|
+
version: "22.2.2",
|
|
300
|
+
ngImport: i0,
|
|
301
|
+
type: HotCellRendererComponent,
|
|
302
|
+
decorators: [{
|
|
303
|
+
type: Component,
|
|
304
|
+
args: [{
|
|
305
|
+
selector: "hot-cell-renderer",
|
|
306
|
+
template: `<!-- This is an abstract component. Extend this component and provide your own template. -->`,
|
|
307
|
+
standalone: true,
|
|
308
|
+
changeDetection: ChangeDetectionStrategy.OnPush
|
|
309
|
+
}]
|
|
310
|
+
}]
|
|
311
|
+
});
|
|
312
|
+
var HotCellEditorBase = class HotCellEditorBase {
|
|
313
|
+
heightFitParentContainer = 100;
|
|
314
|
+
widthFitParentContainer = 100;
|
|
315
|
+
row;
|
|
316
|
+
column;
|
|
317
|
+
prop;
|
|
318
|
+
originalValue;
|
|
319
|
+
cellProperties;
|
|
320
|
+
finishEdit = new EventEmitter();
|
|
321
|
+
cancelEdit = new EventEmitter();
|
|
322
|
+
value;
|
|
323
|
+
getValue() {
|
|
324
|
+
return this.value;
|
|
325
|
+
}
|
|
326
|
+
setValue(value) {
|
|
327
|
+
this.value = value;
|
|
328
|
+
}
|
|
329
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
330
|
+
minVersion: "12.0.0",
|
|
331
|
+
version: "22.2.2",
|
|
332
|
+
ngImport: i0,
|
|
333
|
+
type: HotCellEditorBase,
|
|
334
|
+
deps: [],
|
|
335
|
+
target: i0.ɵɵFactoryTarget.Directive
|
|
336
|
+
});
|
|
337
|
+
static ɵdir = i0.ɵɵngDeclareDirective({
|
|
338
|
+
minVersion: "14.0.0",
|
|
339
|
+
version: "22.2.2",
|
|
340
|
+
type: HotCellEditorBase,
|
|
341
|
+
isStandalone: true,
|
|
342
|
+
inputs: {
|
|
343
|
+
row: "row",
|
|
344
|
+
column: "column",
|
|
345
|
+
prop: "prop",
|
|
346
|
+
originalValue: "originalValue",
|
|
347
|
+
cellProperties: "cellProperties"
|
|
348
|
+
},
|
|
349
|
+
outputs: {
|
|
350
|
+
finishEdit: "finishEdit",
|
|
351
|
+
cancelEdit: "cancelEdit"
|
|
352
|
+
},
|
|
353
|
+
host: { properties: {
|
|
354
|
+
"style.height.%": "this.heightFitParentContainer",
|
|
355
|
+
"style.width.%": "this.widthFitParentContainer"
|
|
356
|
+
} },
|
|
357
|
+
ngImport: i0
|
|
358
|
+
});
|
|
359
|
+
};
|
|
360
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
361
|
+
minVersion: "12.0.0",
|
|
362
|
+
version: "22.2.2",
|
|
363
|
+
ngImport: i0,
|
|
364
|
+
type: HotCellEditorBase,
|
|
365
|
+
decorators: [{ type: Directive }],
|
|
366
|
+
propDecorators: {
|
|
367
|
+
heightFitParentContainer: [{
|
|
368
|
+
type: HostBinding,
|
|
369
|
+
args: ["style.height.%"]
|
|
370
|
+
}],
|
|
371
|
+
widthFitParentContainer: [{
|
|
372
|
+
type: HostBinding,
|
|
373
|
+
args: ["style.width.%"]
|
|
374
|
+
}],
|
|
375
|
+
row: [{ type: Input }],
|
|
376
|
+
column: [{ type: Input }],
|
|
377
|
+
prop: [{ type: Input }],
|
|
378
|
+
originalValue: [{ type: Input }],
|
|
379
|
+
cellProperties: [{ type: Input }],
|
|
380
|
+
finishEdit: [{ type: Output }],
|
|
381
|
+
cancelEdit: [{ type: Output }]
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
var HotCellEditorComponent = class HotCellEditorComponent extends HotCellEditorBase {
|
|
385
|
+
static EDITOR_MARKER = Symbol("HotCellEditorComponent");
|
|
386
|
+
tabindex = -1;
|
|
387
|
+
dataHotInput = "";
|
|
388
|
+
handsontableInputClass = true;
|
|
389
|
+
onClose() {}
|
|
390
|
+
onOpen(event) {}
|
|
391
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
392
|
+
minVersion: "12.0.0",
|
|
393
|
+
version: "22.2.2",
|
|
394
|
+
ngImport: i0,
|
|
395
|
+
type: HotCellEditorComponent,
|
|
396
|
+
deps: null,
|
|
397
|
+
target: i0.ɵɵFactoryTarget.Directive
|
|
398
|
+
});
|
|
399
|
+
static ɵdir = i0.ɵɵngDeclareDirective({
|
|
400
|
+
minVersion: "14.0.0",
|
|
401
|
+
version: "22.2.2",
|
|
402
|
+
type: HotCellEditorComponent,
|
|
403
|
+
isStandalone: true,
|
|
404
|
+
host: { properties: {
|
|
405
|
+
"attr.tabindex": "this.tabindex",
|
|
406
|
+
"attr.data-hot-input": "this.dataHotInput",
|
|
407
|
+
"class.handsontableInput": "this.handsontableInputClass"
|
|
408
|
+
} },
|
|
409
|
+
usesInheritance: true,
|
|
410
|
+
ngImport: i0
|
|
411
|
+
});
|
|
412
|
+
};
|
|
413
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
414
|
+
minVersion: "12.0.0",
|
|
415
|
+
version: "22.2.2",
|
|
416
|
+
ngImport: i0,
|
|
417
|
+
type: HotCellEditorComponent,
|
|
418
|
+
decorators: [{ type: Directive }],
|
|
419
|
+
propDecorators: {
|
|
420
|
+
tabindex: [{
|
|
421
|
+
type: HostBinding,
|
|
422
|
+
args: ["attr.tabindex"]
|
|
423
|
+
}],
|
|
424
|
+
dataHotInput: [{
|
|
425
|
+
type: HostBinding,
|
|
426
|
+
args: ["attr.data-hot-input"]
|
|
427
|
+
}],
|
|
428
|
+
handsontableInputClass: [{
|
|
429
|
+
type: HostBinding,
|
|
430
|
+
args: ["class.handsontableInput"]
|
|
431
|
+
}]
|
|
432
|
+
}
|
|
433
|
+
});
|
|
447
434
|
const FactoryEditorAdapter = (componentRef) => editorFactory({
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
},
|
|
502
|
-
getValue: (editor) => editor._componentRef.instance.getValue(),
|
|
503
|
-
setValue: (editor, value) => {
|
|
504
|
-
editor.value = value;
|
|
505
|
-
editor._componentRef.instance.setValue(value);
|
|
506
|
-
editor._componentRef.changeDetectorRef.detectChanges();
|
|
507
|
-
},
|
|
435
|
+
position: componentRef.instance.position,
|
|
436
|
+
shortcuts: componentRef.instance.shortcuts,
|
|
437
|
+
shortcutsGroup: componentRef.instance.shortcutsGroup,
|
|
438
|
+
config: componentRef.instance.config,
|
|
439
|
+
init(editor) {
|
|
440
|
+
editor._componentRef = componentRef;
|
|
441
|
+
editor._editorPlaceHolderRef = void 0;
|
|
442
|
+
editor._finishEditSubscription = void 0;
|
|
443
|
+
editor._cancelEditSubscription = void 0;
|
|
444
|
+
createEditorPlaceholder(editor, editor.hot._angularEnvironmentInjector);
|
|
445
|
+
editor.input = editor._editorPlaceHolderRef?.location.nativeElement ?? document.createElement("div");
|
|
446
|
+
editor._afterRowResizeCallback = () => {
|
|
447
|
+
if (editor.isOpened()) applyPropsToEditor(editor);
|
|
448
|
+
};
|
|
449
|
+
editor._afterColumnResizeCallback = () => {
|
|
450
|
+
if (editor.isOpened()) applyPropsToEditor(editor);
|
|
451
|
+
};
|
|
452
|
+
editor._afterDestroyCallback = () => {
|
|
453
|
+
cleanupSubscriptions(editor);
|
|
454
|
+
if (editor._editorPlaceHolderRef) editor._editorPlaceHolderRef.destroy();
|
|
455
|
+
};
|
|
456
|
+
editor.hot.addHook("afterRowResize", editor._afterRowResizeCallback);
|
|
457
|
+
editor.hot.addHook("afterColumnResize", editor._afterColumnResizeCallback);
|
|
458
|
+
editor.hot.addHook("afterDestroy", editor._afterDestroyCallback);
|
|
459
|
+
},
|
|
460
|
+
afterInit: (editor) => editor._componentRef.instance.afterInit?.(editor),
|
|
461
|
+
beforeOpen: (editor, context) => {
|
|
462
|
+
cleanupSubscriptions(editor);
|
|
463
|
+
applyPropsToEditor(editor);
|
|
464
|
+
editor._finishEditSubscription = editor._componentRef.instance.finishEdit.pipe(take(1)).subscribe(() => {
|
|
465
|
+
editor.finishEditing();
|
|
466
|
+
});
|
|
467
|
+
editor._cancelEditSubscription = editor._componentRef.instance.cancelEdit.pipe(take(1)).subscribe(() => {
|
|
468
|
+
editor.cancelChanges();
|
|
469
|
+
});
|
|
470
|
+
editor._componentRef.instance.beforeOpen?.(editor, context);
|
|
471
|
+
},
|
|
472
|
+
afterOpen: (editor, event) => {
|
|
473
|
+
editor._componentRef.instance.afterOpen?.(editor, event);
|
|
474
|
+
},
|
|
475
|
+
onFocus: (editor) => editor._componentRef.instance.onFocus?.(editor),
|
|
476
|
+
afterClose: (editor) => {
|
|
477
|
+
resetEditorState(editor);
|
|
478
|
+
editor._editorPlaceHolderRef?.changeDetectorRef.detectChanges();
|
|
479
|
+
editor._editorPlaceHolderRef?.instance.detachEditor();
|
|
480
|
+
editor._componentRef.instance.afterClose?.(editor);
|
|
481
|
+
},
|
|
482
|
+
getValue: (editor) => editor._componentRef.instance.getValue(),
|
|
483
|
+
setValue: (editor, value) => {
|
|
484
|
+
editor.value = value;
|
|
485
|
+
editor._componentRef.instance.setValue(value);
|
|
486
|
+
editor._componentRef.changeDetectorRef.detectChanges();
|
|
487
|
+
}
|
|
508
488
|
});
|
|
509
|
-
/**
|
|
510
|
-
* Creates the editor placeholder component.
|
|
511
|
-
* @param editor The editor instance.
|
|
512
|
-
* @param injector The environment injector from Angular.
|
|
513
|
-
*/
|
|
514
489
|
function createEditorPlaceholder(editor, injector) {
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
}
|
|
518
|
-
editor._editorPlaceHolderRef = createComponent(CustomEditorPlaceholderComponent, {
|
|
519
|
-
environmentInjector: injector,
|
|
520
|
-
});
|
|
490
|
+
if (!injector) return;
|
|
491
|
+
editor._editorPlaceHolderRef = createComponent(CustomEditorPlaceholderComponent, { environmentInjector: injector });
|
|
521
492
|
}
|
|
522
|
-
/**
|
|
523
|
-
* Applies properties to the custom Angular editor and editor placeholder.
|
|
524
|
-
* Updates position, size, and cell context information.
|
|
525
|
-
* @param editor The editor instance.
|
|
526
|
-
*/
|
|
527
493
|
function applyPropsToEditor(editor) {
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
editor._editorPlaceHolderRef.setInput('componentRef', editor._componentRef);
|
|
542
|
-
editor._editorPlaceHolderRef.changeDetectorRef.detectChanges();
|
|
494
|
+
if (!editor._componentRef || !editor._editorPlaceHolderRef) return;
|
|
495
|
+
editor._componentRef.setInput("originalValue", editor.originalValue);
|
|
496
|
+
editor._componentRef.setInput("row", editor.row);
|
|
497
|
+
editor._componentRef.setInput("column", editor.col);
|
|
498
|
+
editor._componentRef.setInput("prop", editor.prop);
|
|
499
|
+
editor._componentRef.setInput("cellProperties", editor.cellProperties);
|
|
500
|
+
const rect = editor.hot.getCell(editor.row, editor.col)?.getBoundingClientRect();
|
|
501
|
+
editor._editorPlaceHolderRef.setInput("placeholderCustomClass", "");
|
|
502
|
+
editor._editorPlaceHolderRef.setInput("height", rect?.height ?? 0);
|
|
503
|
+
editor._editorPlaceHolderRef.setInput("width", rect?.width ?? 0);
|
|
504
|
+
editor._editorPlaceHolderRef.setInput("isVisible", true);
|
|
505
|
+
editor._editorPlaceHolderRef.setInput("componentRef", editor._componentRef);
|
|
506
|
+
editor._editorPlaceHolderRef.changeDetectorRef.detectChanges();
|
|
543
507
|
}
|
|
544
|
-
/**
|
|
545
|
-
* Resets the editor placeholder state.
|
|
546
|
-
* Clears all positioning and visibility settings.
|
|
547
|
-
* @param editor The editor instance.
|
|
548
|
-
*/
|
|
549
508
|
function resetEditorState(editor) {
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
editor._editorPlaceHolderRef.setInput('isVisible', false);
|
|
558
|
-
editor._editorPlaceHolderRef.setInput('componentRef', undefined);
|
|
509
|
+
if (!editor._editorPlaceHolderRef) return;
|
|
510
|
+
editor._editorPlaceHolderRef.setInput("top", void 0);
|
|
511
|
+
editor._editorPlaceHolderRef.setInput("left", void 0);
|
|
512
|
+
editor._editorPlaceHolderRef.setInput("height", void 0);
|
|
513
|
+
editor._editorPlaceHolderRef.setInput("width", void 0);
|
|
514
|
+
editor._editorPlaceHolderRef.setInput("isVisible", false);
|
|
515
|
+
editor._editorPlaceHolderRef.setInput("componentRef", void 0);
|
|
559
516
|
}
|
|
560
|
-
/**
|
|
561
|
-
* Cleans up existing subscriptions.
|
|
562
|
-
* @param editor The editor instance.
|
|
563
|
-
*/
|
|
564
517
|
function cleanupSubscriptions(editor) {
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
/**
|
|
576
|
-
* Abstract base component for creating advanced custom cell renderer components for Handsontable.
|
|
577
|
-
*
|
|
578
|
-
* Extend this component and provide your own template to implement a custom renderer.
|
|
579
|
-
* Unlike {@link HotCellRendererComponent}, this variant also accepts object and array values.
|
|
580
|
-
*
|
|
581
|
-
* @template TValue - The type of the component renderer.
|
|
582
|
-
* @template TProps - The type of additional renderer properties.
|
|
583
|
-
*/
|
|
584
|
-
class HotCellRendererAdvancedComponent extends HotCellRendererBase {
|
|
585
|
-
static RENDERER_MARKER = Symbol('HotCellRendererAdvancedComponent');
|
|
586
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: HotCellRendererAdvancedComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
587
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.25", type: HotCellRendererAdvancedComponent, isStandalone: true, selector: "hot-cell-renderer-advanced", usesInheritance: true, ngImport: i0, template: `<!-- This is an abstract component. Extend this component and provide your own template. -->`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
588
|
-
}
|
|
589
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: HotCellRendererAdvancedComponent, decorators: [{
|
|
590
|
-
type: Component,
|
|
591
|
-
args: [{
|
|
592
|
-
selector: 'hot-cell-renderer-advanced',
|
|
593
|
-
template: `<!-- This is an abstract component. Extend this component and provide your own template. -->`,
|
|
594
|
-
standalone: true,
|
|
595
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
596
|
-
}]
|
|
597
|
-
}] });
|
|
598
|
-
|
|
599
|
-
/**
|
|
600
|
-
* Abstract class representing an advanced Handsontable cell editor in Angular.
|
|
601
|
-
*
|
|
602
|
-
* Extend this class and decorate the subclass with `@Component()` to implement a custom editor.
|
|
603
|
-
* Unlike {@link HotCellEditorComponent}, this variant also accepts object and array values
|
|
604
|
-
* and provides additional lifecycle hooks and positioning options.
|
|
605
|
-
*/
|
|
606
|
-
class HotCellEditorAdvancedComponent extends HotCellEditorBase {
|
|
607
|
-
static EDITOR_MARKER = Symbol('HotCellEditorAdvancedComponent');
|
|
608
|
-
/** Event triggered by Handsontable on focusing the editor. Available in advanced mode. */
|
|
609
|
-
onFocus(editor) { }
|
|
610
|
-
/** The position of the editor in the DOM. Available in advanced mode. */
|
|
611
|
-
position = 'container';
|
|
612
|
-
/** The shortcuts available for the editor. Available in advanced mode. */
|
|
613
|
-
shortcuts;
|
|
614
|
-
/** The group name for the shortcuts. Available in advanced mode. */
|
|
615
|
-
shortcutsGroup;
|
|
616
|
-
/** Configuration object. Available in advanced mode. */
|
|
617
|
-
config;
|
|
618
|
-
/** Lifecycle hook called after the editor is opened. Available in advanced mode. */
|
|
619
|
-
afterOpen(editor, event) { }
|
|
620
|
-
/** Lifecycle hook called after the editor is closed. Available in advanced mode. */
|
|
621
|
-
afterClose(editor) { }
|
|
622
|
-
/** Lifecycle hook called after the editor is initialized. Available in advanced mode. */
|
|
623
|
-
afterInit(editor) { }
|
|
624
|
-
/** Lifecycle hook called before the editor is opened. Available in advanced mode. */
|
|
625
|
-
beforeOpen(editor, { row, col, prop, td, originalValue, cellProperties, }) { }
|
|
626
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: HotCellEditorAdvancedComponent, deps: null, target: i0.ɵɵFactoryTarget.Directive });
|
|
627
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.25", type: HotCellEditorAdvancedComponent, isStandalone: true, usesInheritance: true, ngImport: i0 });
|
|
518
|
+
if (editor._finishEditSubscription) {
|
|
519
|
+
editor._finishEditSubscription.unsubscribe();
|
|
520
|
+
editor._finishEditSubscription = void 0;
|
|
521
|
+
}
|
|
522
|
+
if (editor._cancelEditSubscription) {
|
|
523
|
+
editor._cancelEditSubscription.unsubscribe();
|
|
524
|
+
editor._cancelEditSubscription = void 0;
|
|
525
|
+
}
|
|
628
526
|
}
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
527
|
+
var HotCellRendererAdvancedComponent = class HotCellRendererAdvancedComponent extends HotCellRendererBase {
|
|
528
|
+
static RENDERER_MARKER = Symbol("HotCellRendererAdvancedComponent");
|
|
529
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
530
|
+
minVersion: "12.0.0",
|
|
531
|
+
version: "22.2.2",
|
|
532
|
+
ngImport: i0,
|
|
533
|
+
type: HotCellRendererAdvancedComponent,
|
|
534
|
+
deps: null,
|
|
535
|
+
target: i0.ɵɵFactoryTarget.Component
|
|
536
|
+
});
|
|
537
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
538
|
+
minVersion: "14.0.0",
|
|
539
|
+
version: "22.2.2",
|
|
540
|
+
type: HotCellRendererAdvancedComponent,
|
|
541
|
+
isStandalone: true,
|
|
542
|
+
selector: "hot-cell-renderer-advanced",
|
|
543
|
+
usesInheritance: true,
|
|
544
|
+
ngImport: i0,
|
|
545
|
+
template: `<!-- This is an abstract component. Extend this component and provide your own template. -->`,
|
|
546
|
+
isInline: true,
|
|
547
|
+
changeDetection: i0.ChangeDetectionStrategy.OnPush
|
|
548
|
+
});
|
|
549
|
+
};
|
|
550
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
551
|
+
minVersion: "12.0.0",
|
|
552
|
+
version: "22.2.2",
|
|
553
|
+
ngImport: i0,
|
|
554
|
+
type: HotCellRendererAdvancedComponent,
|
|
555
|
+
decorators: [{
|
|
556
|
+
type: Component,
|
|
557
|
+
args: [{
|
|
558
|
+
selector: "hot-cell-renderer-advanced",
|
|
559
|
+
template: `<!-- This is an abstract component. Extend this component and provide your own template. -->`,
|
|
560
|
+
standalone: true,
|
|
561
|
+
changeDetection: ChangeDetectionStrategy.OnPush
|
|
562
|
+
}]
|
|
563
|
+
}]
|
|
564
|
+
});
|
|
565
|
+
var HotCellEditorAdvancedComponent = class HotCellEditorAdvancedComponent extends HotCellEditorBase {
|
|
566
|
+
static EDITOR_MARKER = Symbol("HotCellEditorAdvancedComponent");
|
|
567
|
+
onFocus(editor) {}
|
|
568
|
+
position = "container";
|
|
569
|
+
shortcuts;
|
|
570
|
+
shortcutsGroup;
|
|
571
|
+
config;
|
|
572
|
+
afterOpen(editor, event) {}
|
|
573
|
+
afterClose(editor) {}
|
|
574
|
+
afterInit(editor) {}
|
|
575
|
+
beforeOpen(editor, { row, col, prop, td, originalValue, cellProperties }) {}
|
|
576
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
577
|
+
minVersion: "12.0.0",
|
|
578
|
+
version: "22.2.2",
|
|
579
|
+
ngImport: i0,
|
|
580
|
+
type: HotCellEditorAdvancedComponent,
|
|
581
|
+
deps: null,
|
|
582
|
+
target: i0.ɵɵFactoryTarget.Directive
|
|
583
|
+
});
|
|
584
|
+
static ɵdir = i0.ɵɵngDeclareDirective({
|
|
585
|
+
minVersion: "14.0.0",
|
|
586
|
+
version: "22.2.2",
|
|
587
|
+
type: HotCellEditorAdvancedComponent,
|
|
588
|
+
isStandalone: true,
|
|
589
|
+
usesInheritance: true,
|
|
590
|
+
ngImport: i0
|
|
591
|
+
});
|
|
592
|
+
};
|
|
593
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
594
|
+
minVersion: "12.0.0",
|
|
595
|
+
version: "22.2.2",
|
|
596
|
+
ngImport: i0,
|
|
597
|
+
type: HotCellEditorAdvancedComponent,
|
|
598
|
+
decorators: [{ type: Directive }]
|
|
599
|
+
});
|
|
600
|
+
const INVALID_RENDERER_WARNING = "The provided renderer component was not recognized as a valid custom renderer. It must either extend HotCellRendererComponent or be a valid TemplateRef. Please ensure that your custom renderer is implemented correctly and imported from the proper source.";
|
|
601
|
+
const INVALID_ADVANCED_RENDERER_WARNING = "The provided renderer component was not recognized as a valid custom renderer. It must either extend HotCellRendererAdvancedComponent. Please ensure that your custom renderer is implemented correctly and imported from the proper source.";
|
|
641
602
|
const RENDERER_INPUT_KEYS = [
|
|
642
|
-
|
|
603
|
+
"instance",
|
|
604
|
+
"td",
|
|
605
|
+
"row",
|
|
606
|
+
"col",
|
|
607
|
+
"prop",
|
|
608
|
+
"value",
|
|
609
|
+
"cellProperties"
|
|
643
610
|
];
|
|
644
|
-
/**
|
|
645
|
-
* Type guard that checks if the given object is a TemplateRef.
|
|
646
|
-
*
|
|
647
|
-
* @param obj - The object to check.
|
|
648
|
-
* @returns True if the object is a TemplateRef; otherwise, false.
|
|
649
|
-
*/
|
|
650
611
|
function isTemplateRef(obj) {
|
|
651
|
-
|
|
612
|
+
return !!obj && typeof obj.createEmbeddedView === "function";
|
|
652
613
|
}
|
|
653
|
-
/**
|
|
654
|
-
* Type guard to check if an object is an instance of HotCellRendererComponent.
|
|
655
|
-
*
|
|
656
|
-
* @param obj - The object to check.
|
|
657
|
-
* @returns True if the object is a HotCellRendererComponent, false otherwise.
|
|
658
|
-
*/
|
|
659
614
|
function isHotCellRendererComponent(obj) {
|
|
660
|
-
|
|
615
|
+
return obj?.RENDERER_MARKER === HotCellRendererComponent.RENDERER_MARKER;
|
|
661
616
|
}
|
|
662
|
-
/**
|
|
663
|
-
* Type guard to check if an object is an instance of HotCellRendererAdvancedComponent.
|
|
664
|
-
*
|
|
665
|
-
* @param obj - The object to check.
|
|
666
|
-
* @returns True if the object is a HotCellRendererAdvancedComponent, false otherwise.
|
|
667
|
-
*/
|
|
668
617
|
function isAdvancedHotCellRendererComponent(obj) {
|
|
669
|
-
|
|
670
|
-
}
|
|
671
|
-
/**
|
|
672
|
-
* Service for dynamically creating Angular components or templates as custom renderers for Handsontable.
|
|
673
|
-
*
|
|
674
|
-
* This service allows you to create a renderer function that wraps a given Angular component or TemplateRef
|
|
675
|
-
* so that it can be used as a Handsontable renderer.
|
|
676
|
-
*
|
|
677
|
-
* @example
|
|
678
|
-
* const customRenderer = dynamicComponentService.createRendererFromComponent(MyRendererComponent, { someProp: value });
|
|
679
|
-
* // Use customRenderer in your Handsontable configuration
|
|
680
|
-
*/
|
|
681
|
-
class DynamicComponentService {
|
|
682
|
-
appRef;
|
|
683
|
-
environmentInjector;
|
|
684
|
-
// Track Angular component refs and embedded views keyed by the TD element they are attached to.
|
|
685
|
-
// When a cell is re-rendered the previous component is destroyed before a new one is created.
|
|
686
|
-
_tdComponentRefs = new WeakMap();
|
|
687
|
-
_tdEmbeddedViews = new WeakMap();
|
|
688
|
-
// Per-instance registries of every renderer ref/view currently attached to the application.
|
|
689
|
-
// The WeakMaps above only allow per-TD lookup; these sets let us sweep refs whose TD was dropped
|
|
690
|
-
// from Handsontable's virtual viewport (scrolling, updateData), which would otherwise stay
|
|
691
|
-
// attached to ApplicationRef forever and leak both memory and change-detection work.
|
|
692
|
-
//
|
|
693
|
-
// The registries are scoped per Handsontable instance (not one global set) because this service
|
|
694
|
-
// is a root singleton shared by every <hot-table>. A global sweep would scan the cells of every
|
|
695
|
-
// table on the page on each `afterViewRender`, i.e. on every scroll frame of any one of them.
|
|
696
|
-
// Keying by instance bounds each sweep to the cells of the table that actually re-rendered.
|
|
697
|
-
_instanceComponentRefs = new WeakMap();
|
|
698
|
-
_instanceEmbeddedViews = new WeakMap();
|
|
699
|
-
// Instances we already wired the sweep hook into, so each instance is hooked at most once.
|
|
700
|
-
_hookedInstances = new WeakSet();
|
|
701
|
-
constructor(appRef, environmentInjector) {
|
|
702
|
-
this.appRef = appRef;
|
|
703
|
-
this.environmentInjector = environmentInjector;
|
|
704
|
-
}
|
|
705
|
-
/**
|
|
706
|
-
* Creates a custom renderer function for Handsontable from an Angular component or TemplateRef.
|
|
707
|
-
* The generated renderer function will be used by Handsontable to render cell content.
|
|
708
|
-
*
|
|
709
|
-
* @param component - The Angular component type or TemplateRef to use as renderer.
|
|
710
|
-
* @param componentProps - An object containing additional properties to use by the renderer.
|
|
711
|
-
* @param register - If true, registers the renderer with Handsontable using the component's name.
|
|
712
|
-
* @returns A renderer function that can be used in Handsontable's configuration.
|
|
713
|
-
*/
|
|
714
|
-
createRendererFromComponent(component, componentProps = {}, register = false) {
|
|
715
|
-
let registered = false;
|
|
716
|
-
return (instance, td, row, col, prop, value, cellProperties) => {
|
|
717
|
-
const properties = {
|
|
718
|
-
value,
|
|
719
|
-
instance,
|
|
720
|
-
td,
|
|
721
|
-
row,
|
|
722
|
-
col,
|
|
723
|
-
prop,
|
|
724
|
-
cellProperties,
|
|
725
|
-
};
|
|
726
|
-
cellProperties.rendererProps = componentProps;
|
|
727
|
-
baseRenderer.call(this, instance, td, row, col, prop, value, cellProperties);
|
|
728
|
-
this.registerSweepHook(instance);
|
|
729
|
-
if (isTemplateRef(component)) {
|
|
730
|
-
// Embedded views carry a per-render context, so they are always rebuilt.
|
|
731
|
-
this.replaceCellContent(instance, td);
|
|
732
|
-
const embeddedView = this.attachTemplateToElement(component, td, properties);
|
|
733
|
-
this.trackEmbeddedView(instance, td, embeddedView);
|
|
734
|
-
}
|
|
735
|
-
else if (isHotCellRendererComponent(component)) {
|
|
736
|
-
this.renderComponent(td, component, properties);
|
|
737
|
-
}
|
|
738
|
-
else {
|
|
739
|
-
console.warn(INVALID_RENDERER_WARNING);
|
|
740
|
-
}
|
|
741
|
-
if (register && !registered && isHotCellRendererComponent(component)) {
|
|
742
|
-
Handsontable.renderers.registerRenderer(component.name, component);
|
|
743
|
-
registered = true;
|
|
744
|
-
}
|
|
745
|
-
return td;
|
|
746
|
-
};
|
|
747
|
-
}
|
|
748
|
-
/**
|
|
749
|
-
* Creates a custom renderer function using rendererFactory from Handsontable.
|
|
750
|
-
* This is an alternative implementation that uses the factory pattern.
|
|
751
|
-
*
|
|
752
|
-
* @param component - The Angular component type to use as renderer.
|
|
753
|
-
* @param componentProps - An object containing additional properties to use by the renderer.
|
|
754
|
-
* @param register - If true, registers the renderer with Handsontable using the component's name.
|
|
755
|
-
* @returns A renderer function that can be used in Handsontable's configuration.
|
|
756
|
-
*/
|
|
757
|
-
createRendererWithFactory(component, componentProps = {}, register = false) {
|
|
758
|
-
let registered = false;
|
|
759
|
-
return rendererFactory(({ instance, td, row, column, prop, value, cellProperties }) => {
|
|
760
|
-
const properties = {
|
|
761
|
-
value,
|
|
762
|
-
instance,
|
|
763
|
-
td,
|
|
764
|
-
row,
|
|
765
|
-
col: column,
|
|
766
|
-
prop,
|
|
767
|
-
cellProperties,
|
|
768
|
-
};
|
|
769
|
-
cellProperties.rendererProps = componentProps;
|
|
770
|
-
// Apply the base renderer so the TD gets the same base classes/attributes as the
|
|
771
|
-
// createRendererFromComponent path (rendererFactory itself does not call it).
|
|
772
|
-
baseRenderer.call(this, instance, td, row, column, prop, value, cellProperties);
|
|
773
|
-
this.registerSweepHook(instance);
|
|
774
|
-
if (isAdvancedHotCellRendererComponent(component)) {
|
|
775
|
-
this.renderComponent(td, component, properties);
|
|
776
|
-
}
|
|
777
|
-
else {
|
|
778
|
-
console.warn(INVALID_ADVANCED_RENDERER_WARNING);
|
|
779
|
-
}
|
|
780
|
-
if (register && !registered && isAdvancedHotCellRendererComponent(component)) {
|
|
781
|
-
registerRenderer(component.name, component);
|
|
782
|
-
registered = true;
|
|
783
|
-
}
|
|
784
|
-
});
|
|
785
|
-
}
|
|
786
|
-
/**
|
|
787
|
-
* Destroys all renderer components and embedded views attached to cells within a container element.
|
|
788
|
-
* Must be called before destroying the Handsontable instance to prevent Angular component leaks.
|
|
789
|
-
*
|
|
790
|
-
* @param container - The root DOM element of the Handsontable instance.
|
|
791
|
-
* @param instance - The Handsontable instance whose registries should be torn down. When omitted
|
|
792
|
-
* (e.g. test stubs), only refs reachable through TDs still in the container are destroyed.
|
|
793
|
-
*/
|
|
794
|
-
cleanupContainer(container, instance) {
|
|
795
|
-
const compRefs = instance ? this._instanceComponentRefs.get(instance) : undefined;
|
|
796
|
-
const embViews = instance ? this._instanceEmbeddedViews.get(instance) : undefined;
|
|
797
|
-
container.querySelectorAll('td').forEach((td) => {
|
|
798
|
-
const compRef = this._tdComponentRefs.get(td);
|
|
799
|
-
if (compRef) {
|
|
800
|
-
this.destroyComponent(compRef);
|
|
801
|
-
this._tdComponentRefs.delete(td);
|
|
802
|
-
compRefs?.delete(compRef);
|
|
803
|
-
}
|
|
804
|
-
const embView = this._tdEmbeddedViews.get(td);
|
|
805
|
-
if (embView) {
|
|
806
|
-
this.destroyEmbeddedView(embView);
|
|
807
|
-
this._tdEmbeddedViews.delete(td);
|
|
808
|
-
embViews?.delete(embView);
|
|
809
|
-
}
|
|
810
|
-
});
|
|
811
|
-
// The loop above only reaches TDs still present in the container. Refs for cells already
|
|
812
|
-
// dropped from the viewport (but not yet swept) would otherwise be orphaned once this
|
|
813
|
-
// instance's afterViewRender hook is gone after destroy. Tear down whatever is left and drop
|
|
814
|
-
// the per-instance registries so a repeated cleanup call is a no-op. (Entries removed in the
|
|
815
|
-
// loop above are already gone from these sets, so nothing is destroyed twice.)
|
|
816
|
-
compRefs?.forEach((ref) => this.destroyComponent(ref));
|
|
817
|
-
embViews?.forEach((view) => this.destroyEmbeddedView(view));
|
|
818
|
-
if (instance) {
|
|
819
|
-
this._instanceComponentRefs.delete(instance);
|
|
820
|
-
this._instanceEmbeddedViews.delete(instance);
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
|
-
/**
|
|
824
|
-
* Registers a one-time `afterViewRender` hook on the given Handsontable instance that sweeps
|
|
825
|
-
* renderer refs whose TD is no longer connected to the document. Handsontable recycles a pool of
|
|
826
|
-
* TD elements while virtualizing rows; cells that leave the viewport are never re-rendered, so
|
|
827
|
-
* without this sweep their Angular components stay attached to ApplicationRef and leak.
|
|
828
|
-
*
|
|
829
|
-
* Guarded against instances that do not expose `addHook` (e.g. test stubs).
|
|
830
|
-
*
|
|
831
|
-
* @param instance - The Handsontable instance whose render cycle drives the sweep.
|
|
832
|
-
*/
|
|
833
|
-
registerSweepHook(instance) {
|
|
834
|
-
if (this._hookedInstances.has(instance) || typeof instance?.addHook !== 'function') {
|
|
835
|
-
return;
|
|
836
|
-
}
|
|
837
|
-
this._hookedInstances.add(instance);
|
|
838
|
-
instance.addHook('afterViewRender', () => this.sweepDetachedViews(instance));
|
|
839
|
-
}
|
|
840
|
-
/**
|
|
841
|
-
* Destroys every renderer ref/view tracked for the given instance whose root node is no longer
|
|
842
|
-
* attached to the document.
|
|
843
|
-
*
|
|
844
|
-
* @param instance - The Handsontable instance whose registries should be swept.
|
|
845
|
-
*/
|
|
846
|
-
sweepDetachedViews(instance) {
|
|
847
|
-
const compRefs = this._instanceComponentRefs.get(instance);
|
|
848
|
-
compRefs?.forEach((ref) => {
|
|
849
|
-
if (!this.isViewConnected(ref.hostView)) {
|
|
850
|
-
this.destroyComponent(ref);
|
|
851
|
-
compRefs.delete(ref);
|
|
852
|
-
}
|
|
853
|
-
});
|
|
854
|
-
const embViews = this._instanceEmbeddedViews.get(instance);
|
|
855
|
-
embViews?.forEach((view) => {
|
|
856
|
-
if (!this.isViewConnected(view)) {
|
|
857
|
-
this.destroyEmbeddedView(view);
|
|
858
|
-
embViews.delete(view);
|
|
859
|
-
}
|
|
860
|
-
});
|
|
861
|
-
}
|
|
862
|
-
/**
|
|
863
|
-
* @returns True if any of the view's root nodes is still connected to the document.
|
|
864
|
-
*/
|
|
865
|
-
isViewConnected(view) {
|
|
866
|
-
return view.rootNodes.some((node) => !!node?.isConnected);
|
|
867
|
-
}
|
|
868
|
-
/**
|
|
869
|
-
* Destroys the renderer ref/view previously attached to a cell and clears the cell content,
|
|
870
|
-
* so a fresh renderer can take over the TD without leaking the old one.
|
|
871
|
-
*
|
|
872
|
-
* @param instance - The Handsontable instance owning the cell, used to update its registries.
|
|
873
|
-
* @param td - The table cell whose previous content should be torn down.
|
|
874
|
-
*/
|
|
875
|
-
replaceCellContent(instance, td) {
|
|
876
|
-
const prevRef = this._tdComponentRefs.get(td);
|
|
877
|
-
if (prevRef) {
|
|
878
|
-
this.destroyComponent(prevRef);
|
|
879
|
-
this._tdComponentRefs.delete(td);
|
|
880
|
-
this._instanceComponentRefs.get(instance)?.delete(prevRef);
|
|
881
|
-
}
|
|
882
|
-
const prevView = this._tdEmbeddedViews.get(td);
|
|
883
|
-
if (prevView) {
|
|
884
|
-
this.destroyEmbeddedView(prevView);
|
|
885
|
-
this._tdEmbeddedViews.delete(td);
|
|
886
|
-
this._instanceEmbeddedViews.get(instance)?.delete(prevView);
|
|
887
|
-
}
|
|
888
|
-
// Not `innerHTML = ''`: that reads as "assign nothing", but `innerHTML` is a Trusted
|
|
889
|
-
// Types sink whatever the value, so under `require-trusted-types-for 'script'` an empty
|
|
890
|
-
// string throws exactly like markup would.
|
|
891
|
-
td.replaceChildren();
|
|
892
|
-
}
|
|
893
|
-
/**
|
|
894
|
-
* Tracks a component ref both by its TD (for fast replacement) and in the instance registry
|
|
895
|
-
* (for sweeping and full teardown).
|
|
896
|
-
*/
|
|
897
|
-
trackComponentRef(instance, td, ref) {
|
|
898
|
-
this._tdComponentRefs.set(td, ref);
|
|
899
|
-
this.registryFor(this._instanceComponentRefs, instance).add(ref);
|
|
900
|
-
}
|
|
901
|
-
/**
|
|
902
|
-
* Tracks an embedded view both by its TD (for fast replacement) and in the instance registry
|
|
903
|
-
* (for sweeping and full teardown).
|
|
904
|
-
*/
|
|
905
|
-
trackEmbeddedView(instance, td, view) {
|
|
906
|
-
this._tdEmbeddedViews.set(td, view);
|
|
907
|
-
this.registryFor(this._instanceEmbeddedViews, instance).add(view);
|
|
908
|
-
}
|
|
909
|
-
/**
|
|
910
|
-
* Returns the per-instance registry set for the given instance, creating it on first use.
|
|
911
|
-
*/
|
|
912
|
-
registryFor(registry, instance) {
|
|
913
|
-
let set = registry.get(instance);
|
|
914
|
-
if (!set) {
|
|
915
|
-
set = new Set();
|
|
916
|
-
registry.set(instance, set);
|
|
917
|
-
}
|
|
918
|
-
return set;
|
|
919
|
-
}
|
|
920
|
-
/**
|
|
921
|
-
* Attaches an embedded view created from a TemplateRef to a given DOM element.
|
|
922
|
-
*
|
|
923
|
-
* @param template - The TemplateRef to create an embedded view from.
|
|
924
|
-
* @param tdEl - The target DOM element (a table cell) to which the view will be appended.
|
|
925
|
-
* @param properties - Context object providing properties to be used within the template.
|
|
926
|
-
* @returns The created EmbeddedViewRef so the caller can track and destroy it later.
|
|
927
|
-
*/
|
|
928
|
-
attachTemplateToElement(template, tdEl, properties) {
|
|
929
|
-
const embeddedView = template.createEmbeddedView({
|
|
930
|
-
$implicit: properties.value,
|
|
931
|
-
...properties,
|
|
932
|
-
});
|
|
933
|
-
embeddedView.detectChanges();
|
|
934
|
-
embeddedView.rootNodes.forEach((node) => {
|
|
935
|
-
tdEl.appendChild(node);
|
|
936
|
-
});
|
|
937
|
-
return embeddedView;
|
|
938
|
-
}
|
|
939
|
-
/**
|
|
940
|
-
* Dynamically creates an Angular component of the given type.
|
|
941
|
-
*
|
|
942
|
-
* @param component - The Angular component type to be created.
|
|
943
|
-
* @param rendererParameters - An object containing input properties to assign to the component instance.
|
|
944
|
-
* @returns The ComponentRef of the dynamically created component.
|
|
945
|
-
*/
|
|
946
|
-
createComponent(component, rendererParameters) {
|
|
947
|
-
const componentRef = createComponent(component, {
|
|
948
|
-
environmentInjector: this.environmentInjector,
|
|
949
|
-
});
|
|
950
|
-
this.applyInputs(componentRef, rendererParameters);
|
|
951
|
-
componentRef.changeDetectorRef.detectChanges();
|
|
952
|
-
this.appRef.attachView(componentRef.hostView);
|
|
953
|
-
return componentRef;
|
|
954
|
-
}
|
|
955
|
-
/**
|
|
956
|
-
* Renders an Angular component into the given cell, recycling the component already attached to
|
|
957
|
-
* the TD when it is of the same type. Handsontable recycles its pool of TD elements heavily while
|
|
958
|
-
* virtualizing rows, so recreating an Angular component on every re-render would cause needless
|
|
959
|
-
* teardown/instantiation churn and GC pressure. When the type matches we only refresh the inputs.
|
|
960
|
-
*
|
|
961
|
-
* @param td - The target table cell.
|
|
962
|
-
* @param component - The renderer component type to render.
|
|
963
|
-
* @param properties - The renderer parameters to feed as component inputs.
|
|
964
|
-
*/
|
|
965
|
-
renderComponent(td, component, properties) {
|
|
966
|
-
const prevRef = this._tdComponentRefs.get(td);
|
|
967
|
-
if (prevRef &&
|
|
968
|
-
prevRef.componentType === component &&
|
|
969
|
-
this.isViewConnected(prevRef.hostView)) {
|
|
970
|
-
this.applyInputs(prevRef, properties);
|
|
971
|
-
prevRef.changeDetectorRef.detectChanges();
|
|
972
|
-
return;
|
|
973
|
-
}
|
|
974
|
-
this.replaceCellContent(properties.instance, td);
|
|
975
|
-
const componentRef = this.createComponent(component, properties);
|
|
976
|
-
this.attachComponentToElement(componentRef, td);
|
|
977
|
-
this.trackComponentRef(properties.instance, td, componentRef);
|
|
978
|
-
}
|
|
979
|
-
/**
|
|
980
|
-
* Assigns every renderer parameter as an input on the given component ref.
|
|
981
|
-
*
|
|
982
|
-
* @param componentRef - The component ref whose inputs should be set.
|
|
983
|
-
* @param rendererParameters - The renderer parameters to assign.
|
|
984
|
-
*/
|
|
985
|
-
applyInputs(componentRef, rendererParameters) {
|
|
986
|
-
RENDERER_INPUT_KEYS.forEach((key) => {
|
|
987
|
-
componentRef.setInput(key, rendererParameters[key]);
|
|
988
|
-
});
|
|
989
|
-
}
|
|
990
|
-
/**
|
|
991
|
-
* Attaches a dynamically created component's view to a specified DOM container element.
|
|
992
|
-
*
|
|
993
|
-
* @param componentRef - The reference to the dynamically created component.
|
|
994
|
-
* @param container - The target DOM element to which the component's root node will be appended.
|
|
995
|
-
*/
|
|
996
|
-
attachComponentToElement(componentRef, container) {
|
|
997
|
-
componentRef.hostView.rootNodes.forEach((node) => {
|
|
998
|
-
container.appendChild(node);
|
|
999
|
-
});
|
|
1000
|
-
}
|
|
1001
|
-
/**
|
|
1002
|
-
* Destroys a dynamically created component and detaches its view from the Angular application.
|
|
1003
|
-
*
|
|
1004
|
-
* Idempotent: a TD recycled after `sweepDetachedViews` already destroyed its ref still maps to that
|
|
1005
|
-
* stale ref in `_tdComponentRefs`, so the next render path may reach this with an already-destroyed
|
|
1006
|
-
* ref. Guarding on `destroyed` skips the redundant detach/destroy instead of relying on Angular's
|
|
1007
|
-
* internal no-op behavior.
|
|
1008
|
-
*
|
|
1009
|
-
* @param componentRef - The reference to the component to be destroyed.
|
|
1010
|
-
*/
|
|
1011
|
-
destroyComponent(componentRef) {
|
|
1012
|
-
const hostView = componentRef.hostView;
|
|
1013
|
-
if (hostView.destroyed) {
|
|
1014
|
-
return;
|
|
1015
|
-
}
|
|
1016
|
-
this.appRef.detachView(hostView);
|
|
1017
|
-
componentRef.destroy();
|
|
1018
|
-
}
|
|
1019
|
-
/**
|
|
1020
|
-
* Destroys an embedded view. Idempotent for the same reason as {@link destroyComponent}: a recycled
|
|
1021
|
-
* TD can still map to an already-destroyed view in `_tdEmbeddedViews`.
|
|
1022
|
-
*
|
|
1023
|
-
* @param view - The embedded view to destroy.
|
|
1024
|
-
*/
|
|
1025
|
-
destroyEmbeddedView(view) {
|
|
1026
|
-
if (view.destroyed) {
|
|
1027
|
-
return;
|
|
1028
|
-
}
|
|
1029
|
-
view.destroy();
|
|
1030
|
-
}
|
|
1031
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: DynamicComponentService, deps: [{ token: i0.ApplicationRef }, { token: i0.EnvironmentInjector }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1032
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: DynamicComponentService, providedIn: 'root' });
|
|
618
|
+
return obj?.RENDERER_MARKER === HotCellRendererAdvancedComponent.RENDERER_MARKER;
|
|
1033
619
|
}
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
620
|
+
var DynamicComponentService = class DynamicComponentService {
|
|
621
|
+
appRef;
|
|
622
|
+
environmentInjector;
|
|
623
|
+
_tdComponentRefs = /* @__PURE__ */ new WeakMap();
|
|
624
|
+
_tdEmbeddedViews = /* @__PURE__ */ new WeakMap();
|
|
625
|
+
_instanceComponentRefs = /* @__PURE__ */ new WeakMap();
|
|
626
|
+
_instanceEmbeddedViews = /* @__PURE__ */ new WeakMap();
|
|
627
|
+
_hookedInstances = /* @__PURE__ */ new WeakSet();
|
|
628
|
+
constructor(appRef, environmentInjector) {
|
|
629
|
+
this.appRef = appRef;
|
|
630
|
+
this.environmentInjector = environmentInjector;
|
|
631
|
+
}
|
|
632
|
+
createRendererFromComponent(component, componentProps = {}, register = false) {
|
|
633
|
+
let registered = false;
|
|
634
|
+
return (instance, td, row, col, prop, value, cellProperties) => {
|
|
635
|
+
const properties = {
|
|
636
|
+
value,
|
|
637
|
+
instance,
|
|
638
|
+
td,
|
|
639
|
+
row,
|
|
640
|
+
col,
|
|
641
|
+
prop,
|
|
642
|
+
cellProperties
|
|
643
|
+
};
|
|
644
|
+
cellProperties.rendererProps = componentProps;
|
|
645
|
+
baseRenderer.call(this, instance, td, row, col, prop, value, cellProperties);
|
|
646
|
+
this.registerSweepHook(instance);
|
|
647
|
+
if (isTemplateRef(component)) {
|
|
648
|
+
this.replaceCellContent(instance, td);
|
|
649
|
+
const embeddedView = this.attachTemplateToElement(component, td, properties);
|
|
650
|
+
this.trackEmbeddedView(instance, td, embeddedView);
|
|
651
|
+
} else if (isHotCellRendererComponent(component)) this.renderComponent(td, component, properties);
|
|
652
|
+
else console.warn(INVALID_RENDERER_WARNING);
|
|
653
|
+
if (register && !registered && isHotCellRendererComponent(component)) {
|
|
654
|
+
Handsontable.renderers.registerRenderer(component.name, component);
|
|
655
|
+
registered = true;
|
|
656
|
+
}
|
|
657
|
+
return td;
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
createRendererWithFactory(component, componentProps = {}, register = false) {
|
|
661
|
+
let registered = false;
|
|
662
|
+
return rendererFactory(({ instance, td, row, column, prop, value, cellProperties }) => {
|
|
663
|
+
const properties = {
|
|
664
|
+
value,
|
|
665
|
+
instance,
|
|
666
|
+
td,
|
|
667
|
+
row,
|
|
668
|
+
col: column,
|
|
669
|
+
prop,
|
|
670
|
+
cellProperties
|
|
671
|
+
};
|
|
672
|
+
cellProperties.rendererProps = componentProps;
|
|
673
|
+
baseRenderer.call(this, instance, td, row, column, prop, value, cellProperties);
|
|
674
|
+
this.registerSweepHook(instance);
|
|
675
|
+
if (isAdvancedHotCellRendererComponent(component)) this.renderComponent(td, component, properties);
|
|
676
|
+
else console.warn(INVALID_ADVANCED_RENDERER_WARNING);
|
|
677
|
+
if (register && !registered && isAdvancedHotCellRendererComponent(component)) {
|
|
678
|
+
registerRenderer(component.name, component);
|
|
679
|
+
registered = true;
|
|
680
|
+
}
|
|
681
|
+
});
|
|
682
|
+
}
|
|
683
|
+
cleanupContainer(container, instance) {
|
|
684
|
+
const compRefs = instance ? this._instanceComponentRefs.get(instance) : void 0;
|
|
685
|
+
const embViews = instance ? this._instanceEmbeddedViews.get(instance) : void 0;
|
|
686
|
+
container.querySelectorAll("td").forEach((td) => {
|
|
687
|
+
const compRef = this._tdComponentRefs.get(td);
|
|
688
|
+
if (compRef) {
|
|
689
|
+
this.destroyComponent(compRef);
|
|
690
|
+
this._tdComponentRefs.delete(td);
|
|
691
|
+
compRefs?.delete(compRef);
|
|
692
|
+
}
|
|
693
|
+
const embView = this._tdEmbeddedViews.get(td);
|
|
694
|
+
if (embView) {
|
|
695
|
+
this.destroyEmbeddedView(embView);
|
|
696
|
+
this._tdEmbeddedViews.delete(td);
|
|
697
|
+
embViews?.delete(embView);
|
|
698
|
+
}
|
|
699
|
+
});
|
|
700
|
+
compRefs?.forEach((ref) => this.destroyComponent(ref));
|
|
701
|
+
embViews?.forEach((view) => this.destroyEmbeddedView(view));
|
|
702
|
+
if (instance) {
|
|
703
|
+
this._instanceComponentRefs.delete(instance);
|
|
704
|
+
this._instanceEmbeddedViews.delete(instance);
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
registerSweepHook(instance) {
|
|
708
|
+
if (this._hookedInstances.has(instance) || typeof instance?.addHook !== "function") return;
|
|
709
|
+
this._hookedInstances.add(instance);
|
|
710
|
+
instance.addHook("afterViewRender", () => this.sweepDetachedViews(instance));
|
|
711
|
+
}
|
|
712
|
+
sweepDetachedViews(instance) {
|
|
713
|
+
const compRefs = this._instanceComponentRefs.get(instance);
|
|
714
|
+
compRefs?.forEach((ref) => {
|
|
715
|
+
if (!this.isViewConnected(ref.hostView)) {
|
|
716
|
+
this.destroyComponent(ref);
|
|
717
|
+
compRefs.delete(ref);
|
|
718
|
+
}
|
|
719
|
+
});
|
|
720
|
+
const embViews = this._instanceEmbeddedViews.get(instance);
|
|
721
|
+
embViews?.forEach((view) => {
|
|
722
|
+
if (!this.isViewConnected(view)) {
|
|
723
|
+
this.destroyEmbeddedView(view);
|
|
724
|
+
embViews.delete(view);
|
|
725
|
+
}
|
|
726
|
+
});
|
|
727
|
+
}
|
|
728
|
+
isViewConnected(view) {
|
|
729
|
+
return view.rootNodes.some((node) => !!node?.isConnected);
|
|
730
|
+
}
|
|
731
|
+
replaceCellContent(instance, td) {
|
|
732
|
+
const prevRef = this._tdComponentRefs.get(td);
|
|
733
|
+
if (prevRef) {
|
|
734
|
+
this.destroyComponent(prevRef);
|
|
735
|
+
this._tdComponentRefs.delete(td);
|
|
736
|
+
this._instanceComponentRefs.get(instance)?.delete(prevRef);
|
|
737
|
+
}
|
|
738
|
+
const prevView = this._tdEmbeddedViews.get(td);
|
|
739
|
+
if (prevView) {
|
|
740
|
+
this.destroyEmbeddedView(prevView);
|
|
741
|
+
this._tdEmbeddedViews.delete(td);
|
|
742
|
+
this._instanceEmbeddedViews.get(instance)?.delete(prevView);
|
|
743
|
+
}
|
|
744
|
+
td.replaceChildren();
|
|
745
|
+
}
|
|
746
|
+
trackComponentRef(instance, td, ref) {
|
|
747
|
+
this._tdComponentRefs.set(td, ref);
|
|
748
|
+
this.registryFor(this._instanceComponentRefs, instance).add(ref);
|
|
749
|
+
}
|
|
750
|
+
trackEmbeddedView(instance, td, view) {
|
|
751
|
+
this._tdEmbeddedViews.set(td, view);
|
|
752
|
+
this.registryFor(this._instanceEmbeddedViews, instance).add(view);
|
|
753
|
+
}
|
|
754
|
+
registryFor(registry, instance) {
|
|
755
|
+
let set = registry.get(instance);
|
|
756
|
+
if (!set) {
|
|
757
|
+
set = /* @__PURE__ */ new Set();
|
|
758
|
+
registry.set(instance, set);
|
|
759
|
+
}
|
|
760
|
+
return set;
|
|
761
|
+
}
|
|
762
|
+
attachTemplateToElement(template, tdEl, properties) {
|
|
763
|
+
const embeddedView = template.createEmbeddedView({
|
|
764
|
+
$implicit: properties.value,
|
|
765
|
+
...properties
|
|
766
|
+
});
|
|
767
|
+
embeddedView.detectChanges();
|
|
768
|
+
embeddedView.rootNodes.forEach((node) => {
|
|
769
|
+
tdEl.appendChild(node);
|
|
770
|
+
});
|
|
771
|
+
return embeddedView;
|
|
772
|
+
}
|
|
773
|
+
createComponent(component, rendererParameters) {
|
|
774
|
+
const componentRef = createComponent(component, { environmentInjector: this.environmentInjector });
|
|
775
|
+
this.applyInputs(componentRef, rendererParameters);
|
|
776
|
+
componentRef.changeDetectorRef.detectChanges();
|
|
777
|
+
this.appRef.attachView(componentRef.hostView);
|
|
778
|
+
return componentRef;
|
|
779
|
+
}
|
|
780
|
+
renderComponent(td, component, properties) {
|
|
781
|
+
const prevRef = this._tdComponentRefs.get(td);
|
|
782
|
+
if (prevRef && prevRef.componentType === component && this.isViewConnected(prevRef.hostView)) {
|
|
783
|
+
this.applyInputs(prevRef, properties);
|
|
784
|
+
prevRef.changeDetectorRef.detectChanges();
|
|
785
|
+
return;
|
|
786
|
+
}
|
|
787
|
+
this.replaceCellContent(properties.instance, td);
|
|
788
|
+
const componentRef = this.createComponent(component, properties);
|
|
789
|
+
this.attachComponentToElement(componentRef, td);
|
|
790
|
+
this.trackComponentRef(properties.instance, td, componentRef);
|
|
791
|
+
}
|
|
792
|
+
applyInputs(componentRef, rendererParameters) {
|
|
793
|
+
RENDERER_INPUT_KEYS.forEach((key) => {
|
|
794
|
+
componentRef.setInput(key, rendererParameters[key]);
|
|
795
|
+
});
|
|
796
|
+
}
|
|
797
|
+
attachComponentToElement(componentRef, container) {
|
|
798
|
+
componentRef.hostView.rootNodes.forEach((node) => {
|
|
799
|
+
container.appendChild(node);
|
|
800
|
+
});
|
|
801
|
+
}
|
|
802
|
+
destroyComponent(componentRef) {
|
|
803
|
+
const hostView = componentRef.hostView;
|
|
804
|
+
if (hostView.destroyed) return;
|
|
805
|
+
this.appRef.detachView(hostView);
|
|
806
|
+
componentRef.destroy();
|
|
807
|
+
}
|
|
808
|
+
destroyEmbeddedView(view) {
|
|
809
|
+
if (view.destroyed) return;
|
|
810
|
+
view.destroy();
|
|
811
|
+
}
|
|
812
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
813
|
+
minVersion: "12.0.0",
|
|
814
|
+
version: "22.2.2",
|
|
815
|
+
ngImport: i0,
|
|
816
|
+
type: DynamicComponentService,
|
|
817
|
+
deps: [{ token: i0.ApplicationRef }, { token: i0.EnvironmentInjector }],
|
|
818
|
+
target: i0.ɵɵFactoryTarget.Injectable
|
|
819
|
+
});
|
|
820
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({
|
|
821
|
+
minVersion: "12.0.0",
|
|
822
|
+
version: "22.2.2",
|
|
823
|
+
ngImport: i0,
|
|
824
|
+
type: DynamicComponentService,
|
|
825
|
+
providedIn: "root"
|
|
826
|
+
});
|
|
827
|
+
};
|
|
828
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
829
|
+
minVersion: "12.0.0",
|
|
830
|
+
version: "22.2.2",
|
|
831
|
+
ngImport: i0,
|
|
832
|
+
type: DynamicComponentService,
|
|
833
|
+
decorators: [{
|
|
834
|
+
type: Injectable,
|
|
835
|
+
args: [{ providedIn: "root" }]
|
|
836
|
+
}],
|
|
837
|
+
ctorParameters: () => [{ type: i0.ApplicationRef }, { type: i0.EnvironmentInjector }]
|
|
838
|
+
});
|
|
1041
839
|
const AVAILABLE_HOOKS_SET = new Set(Handsontable.hooks.getRegistered());
|
|
1042
|
-
const HOT_ZONE_WRAPPED = Symbol(
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
* on-demand component that `BaseEditorAdapter`/`FactoryEditorAdapter` re-prepare on every edit
|
|
1170
|
-
* (`prepare()` re-reads the ref from the *current* column meta and `applyPropsToEditor()` re-applies
|
|
1171
|
-
* the full cell context on each `open()`). The extra `data` check is a defensive guard: when columns
|
|
1172
|
-
* are reordered/shortened so a *different* logical column lands on an index, we build a fresh editor
|
|
1173
|
-
* rather than carry the previous column's instance over, so no custom editor that caches
|
|
1174
|
-
* column-specific config at construction can leak stale state into the new cell.
|
|
1175
|
-
*
|
|
1176
|
-
* @param previousColumn The column at the same index in the previous settings cycle.
|
|
1177
|
-
* @param currentColumn The column now occupying this index.
|
|
1178
|
-
* @param editorType The editor component type requested for the new column.
|
|
1179
|
-
*/
|
|
1180
|
-
reusableEditorRef(previousColumn, currentColumn, editorType) {
|
|
1181
|
-
const previousRef = previousColumn?._editorComponentReference;
|
|
1182
|
-
if (!previousRef || previousRef.componentType !== editorType) {
|
|
1183
|
-
return undefined;
|
|
1184
|
-
}
|
|
1185
|
-
// Same logical column still occupies this index. Columns without a `data` binding are identified
|
|
1186
|
-
// purely by position, so two `undefined` data values compare equal and recycle as before.
|
|
1187
|
-
const sameLogicalColumn = previousColumn?.data ===
|
|
1188
|
-
currentColumn.data;
|
|
1189
|
-
return sameLogicalColumn ? previousRef : undefined;
|
|
1190
|
-
}
|
|
1191
|
-
/**
|
|
1192
|
-
* Updates the column validator for columns with a custom validator.
|
|
1193
|
-
* @param mergedSettings The merged grid settings.
|
|
1194
|
-
*/
|
|
1195
|
-
updateColumnValidatorForGivenCustomValidator(mergedSettings) {
|
|
1196
|
-
if (!Array.isArray(mergedSettings?.columns)) {
|
|
1197
|
-
return;
|
|
1198
|
-
}
|
|
1199
|
-
mergedSettings?.columns
|
|
1200
|
-
?.filter((settings) => this.isCustomValidatorFn(settings.validator))
|
|
1201
|
-
?.forEach((cellSettings) => {
|
|
1202
|
-
const customValidatorFn = cellSettings.validator;
|
|
1203
|
-
cellSettings.validator = (value, callback) => {
|
|
1204
|
-
callback(customValidatorFn(value));
|
|
1205
|
-
};
|
|
1206
|
-
});
|
|
1207
|
-
}
|
|
1208
|
-
isCustomValidatorFn(validator) {
|
|
1209
|
-
return typeof validator === 'function' && validator.length === 1;
|
|
1210
|
-
}
|
|
1211
|
-
isEditorComponentRefType(editor) {
|
|
1212
|
-
// ecmp - we need it to check if the editor is a component
|
|
1213
|
-
return typeof editor === 'function' &&
|
|
1214
|
-
!!editor?.ɵcmp &&
|
|
1215
|
-
editor?.EDITOR_MARKER === HotCellEditorComponent.EDITOR_MARKER;
|
|
1216
|
-
}
|
|
1217
|
-
isAdvancedEditorComponentRefType(editor) {
|
|
1218
|
-
// ecmp - we need it to check if the editor is a component
|
|
1219
|
-
return typeof editor === 'function' &&
|
|
1220
|
-
!!editor?.ɵcmp &&
|
|
1221
|
-
editor?.EDITOR_MARKER === HotCellEditorAdvancedComponent.EDITOR_MARKER;
|
|
1222
|
-
}
|
|
1223
|
-
isRendererComponentRefType(renderer) {
|
|
1224
|
-
// ecmp - we need it to check if the renderer is a component
|
|
1225
|
-
return typeof renderer === 'function' &&
|
|
1226
|
-
!!renderer?.ɵcmp &&
|
|
1227
|
-
renderer?.RENDERER_MARKER === HotCellRendererComponent.RENDERER_MARKER;
|
|
1228
|
-
}
|
|
1229
|
-
isAdvancedRendererComponentRefType(renderer) {
|
|
1230
|
-
// ecmp - we need it to check if the renderer is a component
|
|
1231
|
-
return typeof renderer === 'function' &&
|
|
1232
|
-
!!renderer?.ɵcmp &&
|
|
1233
|
-
renderer?.RENDERER_MARKER === HotCellRendererAdvancedComponent.RENDERER_MARKER;
|
|
1234
|
-
}
|
|
1235
|
-
isTemplateRef(renderer) {
|
|
1236
|
-
return renderer && typeof renderer.createEmbeddedView === 'function';
|
|
1237
|
-
}
|
|
1238
|
-
isCustomRenderer(renderer) {
|
|
1239
|
-
return this.isRendererComponentRefType(renderer) ||
|
|
1240
|
-
this.isTemplateRef(renderer) ||
|
|
1241
|
-
this.isAdvancedRendererComponentRefType(renderer);
|
|
1242
|
-
}
|
|
1243
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: HotSettingsResolver, deps: [{ token: DynamicComponentService }, { token: i0.EnvironmentInjector }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1244
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: HotSettingsResolver });
|
|
1245
|
-
}
|
|
1246
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: HotSettingsResolver, decorators: [{
|
|
1247
|
-
type: Injectable
|
|
1248
|
-
}], ctorParameters: () => [{ type: DynamicComponentService }, { type: i0.EnvironmentInjector }, { type: i0.NgZone }] });
|
|
1249
|
-
|
|
1250
|
-
/**
|
|
1251
|
-
* A constant representing the non-commercial and evaluation license.
|
|
1252
|
-
* */
|
|
1253
|
-
const NON_COMMERCIAL_LICENSE = 'non-commercial-and-evaluation';
|
|
1254
|
-
/**
|
|
1255
|
-
* Type representing a theme name.
|
|
1256
|
-
* Possible values include predefined themes and any custom string.
|
|
1257
|
-
*/
|
|
840
|
+
const HOT_ZONE_WRAPPED = Symbol("hotZoneWrapped");
|
|
841
|
+
var HotSettingsResolver = class HotSettingsResolver {
|
|
842
|
+
dynamicComponentService;
|
|
843
|
+
environmentInjector;
|
|
844
|
+
ngZone;
|
|
845
|
+
constructor(dynamicComponentService, environmentInjector, ngZone) {
|
|
846
|
+
this.dynamicComponentService = dynamicComponentService;
|
|
847
|
+
this.environmentInjector = environmentInjector;
|
|
848
|
+
this.ngZone = ngZone;
|
|
849
|
+
}
|
|
850
|
+
applyCustomSettings(settings, previousColumns) {
|
|
851
|
+
const mergedSettings = { ...settings };
|
|
852
|
+
if (Array.isArray(mergedSettings.columns)) mergedSettings.columns = mergedSettings.columns.map((column) => ({ ...column }));
|
|
853
|
+
this.updateColumnRendererForGivenCustomRenderer(mergedSettings);
|
|
854
|
+
this.updateColumnEditorForGivenCustomEditor(mergedSettings, previousColumns);
|
|
855
|
+
this.updateColumnValidatorForGivenCustomValidator(mergedSettings);
|
|
856
|
+
this.wrapHooksInNgZone(mergedSettings);
|
|
857
|
+
return mergedSettings;
|
|
858
|
+
}
|
|
859
|
+
wrapHooksInNgZone(settings) {
|
|
860
|
+
const ngZone = this.ngZone;
|
|
861
|
+
Object.keys(settings).forEach((key) => {
|
|
862
|
+
if (!AVAILABLE_HOOKS_SET.has(key)) return;
|
|
863
|
+
const option = settings[key];
|
|
864
|
+
if (typeof option === "function" && !option[HOT_ZONE_WRAPPED]) {
|
|
865
|
+
const wrapped = function(...args) {
|
|
866
|
+
return ngZone.run(() => option.apply(this, args));
|
|
867
|
+
};
|
|
868
|
+
wrapped[HOT_ZONE_WRAPPED] = true;
|
|
869
|
+
settings[key] = wrapped;
|
|
870
|
+
}
|
|
871
|
+
});
|
|
872
|
+
}
|
|
873
|
+
updateColumnRendererForGivenCustomRenderer(mergedSettings) {
|
|
874
|
+
if (!Array.isArray(mergedSettings?.columns)) return;
|
|
875
|
+
mergedSettings?.columns?.filter((settings) => this.isCustomRenderer(settings.renderer))?.forEach((cellSettings) => {
|
|
876
|
+
const renderer = cellSettings.renderer;
|
|
877
|
+
const props = cellSettings.rendererProps ?? {};
|
|
878
|
+
if (this.isAdvancedRendererComponentRefType(renderer)) cellSettings.renderer = this.dynamicComponentService.createRendererWithFactory(renderer, props);
|
|
879
|
+
else if (this.isRendererComponentRefType(renderer) || this.isTemplateRef(renderer)) cellSettings.renderer = this.dynamicComponentService.createRendererFromComponent(renderer, props);
|
|
880
|
+
});
|
|
881
|
+
}
|
|
882
|
+
updateColumnEditorForGivenCustomEditor(mergedSettings, previousColumns) {
|
|
883
|
+
if (!Array.isArray(mergedSettings?.columns)) return;
|
|
884
|
+
mergedSettings.columns.forEach((cellSettings, index) => {
|
|
885
|
+
const isAdvanced = this.isAdvancedEditorComponentRefType(cellSettings.editor);
|
|
886
|
+
const isBasic = this.isEditorComponentRefType(cellSettings.editor);
|
|
887
|
+
if (!isAdvanced && !isBasic) return;
|
|
888
|
+
const editorType = cellSettings.editor;
|
|
889
|
+
const reusableRef = this.reusableEditorRef(previousColumns?.[index], cellSettings, editorType);
|
|
890
|
+
const internalSettings = cellSettings;
|
|
891
|
+
const component = reusableRef ?? createComponent(editorType, { environmentInjector: this.environmentInjector });
|
|
892
|
+
internalSettings._editorComponentReference = component;
|
|
893
|
+
if (isAdvanced) cellSettings.editor = FactoryEditorAdapter(component);
|
|
894
|
+
else {
|
|
895
|
+
internalSettings._environmentInjector = this.environmentInjector;
|
|
896
|
+
cellSettings.editor = BaseEditorAdapter;
|
|
897
|
+
}
|
|
898
|
+
});
|
|
899
|
+
}
|
|
900
|
+
reusableEditorRef(previousColumn, currentColumn, editorType) {
|
|
901
|
+
const previousRef = previousColumn?._editorComponentReference;
|
|
902
|
+
if (!previousRef || previousRef.componentType !== editorType) return;
|
|
903
|
+
return previousColumn?.data === currentColumn.data ? previousRef : void 0;
|
|
904
|
+
}
|
|
905
|
+
updateColumnValidatorForGivenCustomValidator(mergedSettings) {
|
|
906
|
+
if (!Array.isArray(mergedSettings?.columns)) return;
|
|
907
|
+
mergedSettings?.columns?.filter((settings) => this.isCustomValidatorFn(settings.validator))?.forEach((cellSettings) => {
|
|
908
|
+
const customValidatorFn = cellSettings.validator;
|
|
909
|
+
cellSettings.validator = (value, callback) => {
|
|
910
|
+
callback(customValidatorFn(value));
|
|
911
|
+
};
|
|
912
|
+
});
|
|
913
|
+
}
|
|
914
|
+
isCustomValidatorFn(validator) {
|
|
915
|
+
return typeof validator === "function" && validator.length === 1;
|
|
916
|
+
}
|
|
917
|
+
isEditorComponentRefType(editor) {
|
|
918
|
+
return typeof editor === "function" && !!editor?.ɵcmp && editor?.EDITOR_MARKER === HotCellEditorComponent.EDITOR_MARKER;
|
|
919
|
+
}
|
|
920
|
+
isAdvancedEditorComponentRefType(editor) {
|
|
921
|
+
return typeof editor === "function" && !!editor?.ɵcmp && editor?.EDITOR_MARKER === HotCellEditorAdvancedComponent.EDITOR_MARKER;
|
|
922
|
+
}
|
|
923
|
+
isRendererComponentRefType(renderer) {
|
|
924
|
+
return typeof renderer === "function" && !!renderer?.ɵcmp && renderer?.RENDERER_MARKER === HotCellRendererComponent.RENDERER_MARKER;
|
|
925
|
+
}
|
|
926
|
+
isAdvancedRendererComponentRefType(renderer) {
|
|
927
|
+
return typeof renderer === "function" && !!renderer?.ɵcmp && renderer?.RENDERER_MARKER === HotCellRendererAdvancedComponent.RENDERER_MARKER;
|
|
928
|
+
}
|
|
929
|
+
isTemplateRef(renderer) {
|
|
930
|
+
return renderer && typeof renderer.createEmbeddedView === "function";
|
|
931
|
+
}
|
|
932
|
+
isCustomRenderer(renderer) {
|
|
933
|
+
return this.isRendererComponentRefType(renderer) || this.isTemplateRef(renderer) || this.isAdvancedRendererComponentRefType(renderer);
|
|
934
|
+
}
|
|
935
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
936
|
+
minVersion: "12.0.0",
|
|
937
|
+
version: "22.2.2",
|
|
938
|
+
ngImport: i0,
|
|
939
|
+
type: HotSettingsResolver,
|
|
940
|
+
deps: [
|
|
941
|
+
{ token: DynamicComponentService },
|
|
942
|
+
{ token: i0.EnvironmentInjector },
|
|
943
|
+
{ token: i0.NgZone }
|
|
944
|
+
],
|
|
945
|
+
target: i0.ɵɵFactoryTarget.Injectable
|
|
946
|
+
});
|
|
947
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({
|
|
948
|
+
minVersion: "12.0.0",
|
|
949
|
+
version: "22.2.2",
|
|
950
|
+
ngImport: i0,
|
|
951
|
+
type: HotSettingsResolver
|
|
952
|
+
});
|
|
953
|
+
};
|
|
954
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
955
|
+
minVersion: "12.0.0",
|
|
956
|
+
version: "22.2.2",
|
|
957
|
+
ngImport: i0,
|
|
958
|
+
type: HotSettingsResolver,
|
|
959
|
+
decorators: [{ type: Injectable }],
|
|
960
|
+
ctorParameters: () => [
|
|
961
|
+
{ type: DynamicComponentService },
|
|
962
|
+
{ type: i0.EnvironmentInjector },
|
|
963
|
+
{ type: i0.NgZone }
|
|
964
|
+
]
|
|
965
|
+
});
|
|
966
|
+
const NON_COMMERCIAL_LICENSE = "non-commercial-and-evaluation";
|
|
1258
967
|
var PredefinedTheme;
|
|
1259
|
-
(function
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
968
|
+
(function(PredefinedTheme) {
|
|
969
|
+
PredefinedTheme["Main"] = "ht-theme-main";
|
|
970
|
+
PredefinedTheme["MainDark"] = "ht-theme-main-dark";
|
|
971
|
+
PredefinedTheme["MainDarkAuto"] = "ht-theme-main-dark-auto";
|
|
972
|
+
PredefinedTheme["Horizon"] = "ht-theme-horizon";
|
|
973
|
+
PredefinedTheme["HorizonDark"] = "ht-theme-horizon-dark";
|
|
974
|
+
PredefinedTheme["HorizonDarkAuto"] = "ht-theme-horizon-dark-auto";
|
|
1266
975
|
})(PredefinedTheme || (PredefinedTheme = {}));
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
const HOT_GLOBAL_CONFIG = new InjectionToken('HOT_GLOBAL_CONFIG', {
|
|
1271
|
-
providedIn: 'root',
|
|
1272
|
-
factory: () => ({})
|
|
976
|
+
const HOT_GLOBAL_CONFIG = new InjectionToken("HOT_GLOBAL_CONFIG", {
|
|
977
|
+
providedIn: "root",
|
|
978
|
+
factory: () => ({})
|
|
1273
979
|
});
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
}
|
|
1339
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: HotGlobalConfigService, deps: [{ token: HOT_GLOBAL_CONFIG }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1340
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: HotGlobalConfigService, providedIn: 'root' });
|
|
1341
|
-
}
|
|
1342
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: HotGlobalConfigService, decorators: [{
|
|
1343
|
-
type: Injectable,
|
|
1344
|
-
args: [{
|
|
1345
|
-
providedIn: 'root',
|
|
1346
|
-
}]
|
|
1347
|
-
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
1348
|
-
type: Inject,
|
|
1349
|
-
args: [HOT_GLOBAL_CONFIG]
|
|
1350
|
-
}] }] });
|
|
1351
|
-
|
|
1352
|
-
const HOT_DESTROYED_WARNING = 'The Handsontable instance bound to this component was destroyed and cannot be' + ' used properly.';
|
|
1353
|
-
/**
|
|
1354
|
-
* The size options that discard the sizes stored by the manual resize plugins when they are passed
|
|
1355
|
-
* to `updateSettings()`.
|
|
1356
|
-
*/
|
|
1357
|
-
const SIZE_SETTING_KEYS = new Set(['rowHeights', 'minRowHeights', 'colWidths']);
|
|
1358
|
-
/**
|
|
1359
|
-
* Compares two size option values. Both hold a number, a string, a function or an array of numbers
|
|
1360
|
-
* or strings, so an element-wise walk is enough - and it is what makes a value written inline in a
|
|
1361
|
-
* template, which is a new array on every change detection run, compare as unchanged.
|
|
1362
|
-
*
|
|
1363
|
-
* A function is compared by reference only. It states no fixed size, and the core plugins ignore it
|
|
1364
|
-
* when deciding whether the sizes were re-declared, so forwarding it changes nothing either way.
|
|
1365
|
-
*
|
|
1366
|
-
* @param currentValue The value the grid currently holds.
|
|
1367
|
-
* @param newValue The value coming from the `settings` input.
|
|
1368
|
-
* @returns `true` when the two state the same sizes.
|
|
1369
|
-
*/
|
|
980
|
+
var HotGlobalConfigService = class HotGlobalConfigService {
|
|
981
|
+
defaultConfig = {};
|
|
982
|
+
configSubject = new BehaviorSubject(this.defaultConfig);
|
|
983
|
+
get config$() {
|
|
984
|
+
return this.configSubject.asObservable();
|
|
985
|
+
}
|
|
986
|
+
constructor(globalConfig) {
|
|
987
|
+
this.defaultConfig = {
|
|
988
|
+
...this.defaultConfig,
|
|
989
|
+
...globalConfig
|
|
990
|
+
};
|
|
991
|
+
this.configSubject.next(this.defaultConfig);
|
|
992
|
+
}
|
|
993
|
+
setConfig(config) {
|
|
994
|
+
this.configSubject.next({
|
|
995
|
+
...this.defaultConfig,
|
|
996
|
+
...config
|
|
997
|
+
});
|
|
998
|
+
}
|
|
999
|
+
getConfig() {
|
|
1000
|
+
return this.configSubject.value;
|
|
1001
|
+
}
|
|
1002
|
+
resetConfig() {
|
|
1003
|
+
this.configSubject.next({ ...this.defaultConfig });
|
|
1004
|
+
}
|
|
1005
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
1006
|
+
minVersion: "12.0.0",
|
|
1007
|
+
version: "22.2.2",
|
|
1008
|
+
ngImport: i0,
|
|
1009
|
+
type: HotGlobalConfigService,
|
|
1010
|
+
deps: [{ token: HOT_GLOBAL_CONFIG }],
|
|
1011
|
+
target: i0.ɵɵFactoryTarget.Injectable
|
|
1012
|
+
});
|
|
1013
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({
|
|
1014
|
+
minVersion: "12.0.0",
|
|
1015
|
+
version: "22.2.2",
|
|
1016
|
+
ngImport: i0,
|
|
1017
|
+
type: HotGlobalConfigService,
|
|
1018
|
+
providedIn: "root"
|
|
1019
|
+
});
|
|
1020
|
+
};
|
|
1021
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
1022
|
+
minVersion: "12.0.0",
|
|
1023
|
+
version: "22.2.2",
|
|
1024
|
+
ngImport: i0,
|
|
1025
|
+
type: HotGlobalConfigService,
|
|
1026
|
+
decorators: [{
|
|
1027
|
+
type: Injectable,
|
|
1028
|
+
args: [{ providedIn: "root" }]
|
|
1029
|
+
}],
|
|
1030
|
+
ctorParameters: () => [{
|
|
1031
|
+
type: void 0,
|
|
1032
|
+
decorators: [{
|
|
1033
|
+
type: Inject,
|
|
1034
|
+
args: [HOT_GLOBAL_CONFIG]
|
|
1035
|
+
}]
|
|
1036
|
+
}]
|
|
1037
|
+
});
|
|
1038
|
+
const HOT_DESTROYED_WARNING = "The Handsontable instance bound to this component was destroyed and cannot be used properly.";
|
|
1039
|
+
const SIZE_SETTING_KEYS = /* @__PURE__ */ new Set([
|
|
1040
|
+
"rowHeights",
|
|
1041
|
+
"minRowHeights",
|
|
1042
|
+
"colWidths"
|
|
1043
|
+
]);
|
|
1370
1044
|
function isSameSizeSetting(currentValue, newValue) {
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
if (Array.isArray(currentValue) && Array.isArray(newValue)) {
|
|
1375
|
-
return currentValue.length === newValue.length &&
|
|
1376
|
-
currentValue.every((value, index) => value === newValue[index]);
|
|
1377
|
-
}
|
|
1378
|
-
return false;
|
|
1045
|
+
if (currentValue === newValue) return true;
|
|
1046
|
+
if (Array.isArray(currentValue) && Array.isArray(newValue)) return currentValue.length === newValue.length && currentValue.every((value, index) => value === newValue[index]);
|
|
1047
|
+
return false;
|
|
1379
1048
|
}
|
|
1380
|
-
|
|
1381
|
-
* The class that makes the container and the host fill their parent. The component styles below
|
|
1382
|
-
* spell the same name, because decorator metadata must stay statically analyzable.
|
|
1383
|
-
*/
|
|
1384
|
-
const FILL_HEIGHT_CLASS_NAME = 'ht-fill-height';
|
|
1385
|
-
/**
|
|
1386
|
-
* A `height` that resolves against the container: a percentage, or a `var()` that may hold one.
|
|
1387
|
-
* The core treats the same two as container-driven in `utils/rootSize.ts`, together with units that
|
|
1388
|
-
* resolve against the viewport or a query container, which do not depend on the container here.
|
|
1389
|
-
*/
|
|
1049
|
+
const FILL_HEIGHT_CLASS_NAME = "ht-fill-height";
|
|
1390
1050
|
const RELATIVE_HEIGHT_PATTERN = /%|\bvar\(/i;
|
|
1391
|
-
class HotTableComponent {
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: HotTableModule });
|
|
1611
|
-
}
|
|
1612
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: HotTableModule, decorators: [{
|
|
1613
|
-
type: NgModule,
|
|
1614
|
-
args: [{
|
|
1615
|
-
imports: [HotTableComponent],
|
|
1616
|
-
exports: [HotTableComponent],
|
|
1617
|
-
}]
|
|
1618
|
-
}] });
|
|
1619
|
-
|
|
1620
|
-
/*
|
|
1621
|
-
* Public API Surface of hot-table
|
|
1622
|
-
*/
|
|
1623
|
-
|
|
1624
|
-
/**
|
|
1625
|
-
* Generated bundle index. Do not edit.
|
|
1626
|
-
*/
|
|
1627
|
-
|
|
1051
|
+
var HotTableComponent = class HotTableComponent {
|
|
1052
|
+
_hotSettingsResolver;
|
|
1053
|
+
_hotConfig;
|
|
1054
|
+
ngZone;
|
|
1055
|
+
environmentInjector;
|
|
1056
|
+
_dynamicComponentService;
|
|
1057
|
+
data = null;
|
|
1058
|
+
settings = {};
|
|
1059
|
+
container;
|
|
1060
|
+
__hotInstance = null;
|
|
1061
|
+
_destroyRef = inject(DestroyRef);
|
|
1062
|
+
_host = inject(ElementRef);
|
|
1063
|
+
constructor(_hotSettingsResolver, _hotConfig, ngZone, environmentInjector, _dynamicComponentService) {
|
|
1064
|
+
this._hotSettingsResolver = _hotSettingsResolver;
|
|
1065
|
+
this._hotConfig = _hotConfig;
|
|
1066
|
+
this.ngZone = ngZone;
|
|
1067
|
+
this.environmentInjector = environmentInjector;
|
|
1068
|
+
this._dynamicComponentService = _dynamicComponentService;
|
|
1069
|
+
}
|
|
1070
|
+
get hotInstance() {
|
|
1071
|
+
if (!this.__hotInstance || !this.__hotInstance.isDestroyed) return this.__hotInstance;
|
|
1072
|
+
else {
|
|
1073
|
+
console.warn(HOT_DESTROYED_WARNING);
|
|
1074
|
+
return null;
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
set hotInstance(hotInstance) {
|
|
1078
|
+
this.__hotInstance = hotInstance;
|
|
1079
|
+
}
|
|
1080
|
+
ngAfterViewInit() {
|
|
1081
|
+
let options = this._hotSettingsResolver.applyCustomSettings(this.settings);
|
|
1082
|
+
const negotiatedSettings = this.getNegotiatedSettings(options);
|
|
1083
|
+
options = {
|
|
1084
|
+
...options,
|
|
1085
|
+
...negotiatedSettings,
|
|
1086
|
+
...this.data != null ? { data: this.data } : {}
|
|
1087
|
+
};
|
|
1088
|
+
this.ngZone.runOutsideAngular(() => {
|
|
1089
|
+
this.hotInstance = new Handsontable.Core(this.container.nativeElement, options);
|
|
1090
|
+
this.hotInstance._angularEnvironmentInjector = this.environmentInjector;
|
|
1091
|
+
this.hotInstance.addHook("beforeHeightChange", (height) => {
|
|
1092
|
+
this.toggleFillHeight(height);
|
|
1093
|
+
return height;
|
|
1094
|
+
});
|
|
1095
|
+
this.hotInstance.init();
|
|
1096
|
+
});
|
|
1097
|
+
this._hotConfig.config$.pipe(skip(1), takeUntilDestroyed(this._destroyRef)).subscribe((config) => {
|
|
1098
|
+
if (this.hotInstance) {
|
|
1099
|
+
const negotiatedSettings = this.getNegotiatedSettings(this.settings);
|
|
1100
|
+
this.updateHotTable(negotiatedSettings);
|
|
1101
|
+
}
|
|
1102
|
+
});
|
|
1103
|
+
}
|
|
1104
|
+
ngOnChanges(changes) {
|
|
1105
|
+
if (this.hotInstance === null) return;
|
|
1106
|
+
if (changes.settings && !changes.settings.firstChange) {
|
|
1107
|
+
const prevColumns = this.__hotInstance?.getSettings().columns;
|
|
1108
|
+
const prevColumnsArray = Array.isArray(prevColumns) ? prevColumns : void 0;
|
|
1109
|
+
const newOptions = this._hotSettingsResolver.applyCustomSettings(changes.settings.currentValue, prevColumnsArray);
|
|
1110
|
+
this.updateHotTable(newOptions);
|
|
1111
|
+
if (prevColumnsArray && Array.isArray(newOptions.columns)) {
|
|
1112
|
+
const reusedRefs = new Set(newOptions.columns.map((column) => column._editorComponentReference).filter((ref) => !!ref));
|
|
1113
|
+
prevColumnsArray.forEach((column) => {
|
|
1114
|
+
if (column._editorComponentReference && !reusedRefs.has(column._editorComponentReference)) column._editorComponentReference.destroy();
|
|
1115
|
+
});
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
if (changes.data && !changes.data.firstChange) this.hotInstance?.updateData(changes.data.currentValue);
|
|
1119
|
+
}
|
|
1120
|
+
ngOnDestroy() {
|
|
1121
|
+
this.ngZone.runOutsideAngular(() => {
|
|
1122
|
+
if (!this.__hotInstance || this.__hotInstance.isDestroyed) return;
|
|
1123
|
+
if (this.container) this._dynamicComponentService.cleanupContainer(this.container.nativeElement, this.__hotInstance);
|
|
1124
|
+
const columns = this.__hotInstance.getSettings().columns;
|
|
1125
|
+
if (columns && Array.isArray(columns)) columns.forEach((column) => {
|
|
1126
|
+
if (column._editorComponentReference) column._editorComponentReference.destroy();
|
|
1127
|
+
});
|
|
1128
|
+
this.__hotInstance.destroy();
|
|
1129
|
+
});
|
|
1130
|
+
}
|
|
1131
|
+
toggleFillHeight(height) {
|
|
1132
|
+
const fillHeight = typeof height === "string" && RELATIVE_HEIGHT_PATTERN.test(height);
|
|
1133
|
+
this.container.nativeElement.classList.toggle(FILL_HEIGHT_CLASS_NAME, fillHeight);
|
|
1134
|
+
this._host.nativeElement.classList.toggle(FILL_HEIGHT_CLASS_NAME, fillHeight);
|
|
1135
|
+
}
|
|
1136
|
+
updateHotTable(newSettings) {
|
|
1137
|
+
if (!this.hotInstance) return;
|
|
1138
|
+
const currentSettings = this.hotInstance.getSettings();
|
|
1139
|
+
const initOnlySettingKeys = new Set(currentSettings?._initOnlySettings ?? []);
|
|
1140
|
+
const filteredSettings = {};
|
|
1141
|
+
for (const key of Object.keys(newSettings)) {
|
|
1142
|
+
if (initOnlySettingKeys.has(key)) continue;
|
|
1143
|
+
if (SIZE_SETTING_KEYS.has(key) && isSameSizeSetting(currentSettings?.[key], newSettings[key])) continue;
|
|
1144
|
+
filteredSettings[key] = newSettings[key];
|
|
1145
|
+
}
|
|
1146
|
+
this.ngZone.runOutsideAngular(() => {
|
|
1147
|
+
this.hotInstance?.updateSettings(filteredSettings, false);
|
|
1148
|
+
});
|
|
1149
|
+
}
|
|
1150
|
+
getNegotiatedSettings(settings) {
|
|
1151
|
+
const hotConfig = this._hotConfig.getConfig();
|
|
1152
|
+
const negotiatedSettings = {};
|
|
1153
|
+
negotiatedSettings.licenseKey = settings.licenseKey ?? hotConfig.license;
|
|
1154
|
+
negotiatedSettings.language = settings.language ?? hotConfig.language;
|
|
1155
|
+
const theme = settings.theme ?? hotConfig.theme;
|
|
1156
|
+
const themeName = settings.themeName ?? hotConfig.themeName;
|
|
1157
|
+
if (theme !== void 0) negotiatedSettings.theme = theme;
|
|
1158
|
+
else if (themeName) negotiatedSettings.themeName = themeName;
|
|
1159
|
+
if (!this.__hotInstance) negotiatedSettings.layoutDirection = settings.layoutDirection ?? hotConfig.layoutDirection;
|
|
1160
|
+
return negotiatedSettings;
|
|
1161
|
+
}
|
|
1162
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
1163
|
+
minVersion: "12.0.0",
|
|
1164
|
+
version: "22.2.2",
|
|
1165
|
+
ngImport: i0,
|
|
1166
|
+
type: HotTableComponent,
|
|
1167
|
+
deps: [
|
|
1168
|
+
{ token: HotSettingsResolver },
|
|
1169
|
+
{ token: HotGlobalConfigService },
|
|
1170
|
+
{ token: i0.NgZone },
|
|
1171
|
+
{ token: i0.EnvironmentInjector },
|
|
1172
|
+
{ token: DynamicComponentService }
|
|
1173
|
+
],
|
|
1174
|
+
target: i0.ɵɵFactoryTarget.Component
|
|
1175
|
+
});
|
|
1176
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
1177
|
+
minVersion: "14.0.0",
|
|
1178
|
+
version: "22.2.2",
|
|
1179
|
+
type: HotTableComponent,
|
|
1180
|
+
isStandalone: true,
|
|
1181
|
+
selector: "hot-table",
|
|
1182
|
+
inputs: {
|
|
1183
|
+
data: "data",
|
|
1184
|
+
settings: "settings"
|
|
1185
|
+
},
|
|
1186
|
+
providers: [HotSettingsResolver],
|
|
1187
|
+
viewQueries: [{
|
|
1188
|
+
propertyName: "container",
|
|
1189
|
+
first: true,
|
|
1190
|
+
predicate: ["container"],
|
|
1191
|
+
descendants: true
|
|
1192
|
+
}],
|
|
1193
|
+
usesOnChanges: true,
|
|
1194
|
+
ngImport: i0,
|
|
1195
|
+
template: "<div #container></div>",
|
|
1196
|
+
isInline: true,
|
|
1197
|
+
styles: [":host{display:block}:where(hot-table.ht-fill-height,hot-table>div.ht-fill-height){height:100%}\n"],
|
|
1198
|
+
encapsulation: i0.ViewEncapsulation.None
|
|
1199
|
+
});
|
|
1200
|
+
};
|
|
1201
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
1202
|
+
minVersion: "12.0.0",
|
|
1203
|
+
version: "22.2.2",
|
|
1204
|
+
ngImport: i0,
|
|
1205
|
+
type: HotTableComponent,
|
|
1206
|
+
decorators: [{
|
|
1207
|
+
type: Component,
|
|
1208
|
+
args: [{
|
|
1209
|
+
selector: "hot-table",
|
|
1210
|
+
template: "<div #container></div>",
|
|
1211
|
+
encapsulation: ViewEncapsulation.None,
|
|
1212
|
+
providers: [HotSettingsResolver],
|
|
1213
|
+
styles: [":host{display:block}:where(hot-table.ht-fill-height,hot-table>div.ht-fill-height){height:100%}\n"]
|
|
1214
|
+
}]
|
|
1215
|
+
}],
|
|
1216
|
+
ctorParameters: () => [
|
|
1217
|
+
{ type: HotSettingsResolver },
|
|
1218
|
+
{ type: HotGlobalConfigService },
|
|
1219
|
+
{ type: i0.NgZone },
|
|
1220
|
+
{ type: i0.EnvironmentInjector },
|
|
1221
|
+
{ type: DynamicComponentService }
|
|
1222
|
+
],
|
|
1223
|
+
propDecorators: {
|
|
1224
|
+
data: [{ type: Input }],
|
|
1225
|
+
settings: [{ type: Input }],
|
|
1226
|
+
container: [{
|
|
1227
|
+
type: ViewChild,
|
|
1228
|
+
args: ["container", { static: false }]
|
|
1229
|
+
}]
|
|
1230
|
+
}
|
|
1231
|
+
});
|
|
1232
|
+
var HotTableModule = class HotTableModule {
|
|
1233
|
+
static version = "0.0.0-next-a26137c-20261014";
|
|
1234
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
1235
|
+
minVersion: "12.0.0",
|
|
1236
|
+
version: "22.2.2",
|
|
1237
|
+
ngImport: i0,
|
|
1238
|
+
type: HotTableModule,
|
|
1239
|
+
deps: [],
|
|
1240
|
+
target: i0.ɵɵFactoryTarget.NgModule
|
|
1241
|
+
});
|
|
1242
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({
|
|
1243
|
+
minVersion: "14.0.0",
|
|
1244
|
+
version: "22.2.2",
|
|
1245
|
+
ngImport: i0,
|
|
1246
|
+
type: HotTableModule,
|
|
1247
|
+
imports: [HotTableComponent],
|
|
1248
|
+
exports: [HotTableComponent]
|
|
1249
|
+
});
|
|
1250
|
+
static ɵinj = i0.ɵɵngDeclareInjector({
|
|
1251
|
+
minVersion: "12.0.0",
|
|
1252
|
+
version: "22.2.2",
|
|
1253
|
+
ngImport: i0,
|
|
1254
|
+
type: HotTableModule
|
|
1255
|
+
});
|
|
1256
|
+
};
|
|
1257
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
1258
|
+
minVersion: "12.0.0",
|
|
1259
|
+
version: "22.2.2",
|
|
1260
|
+
ngImport: i0,
|
|
1261
|
+
type: HotTableModule,
|
|
1262
|
+
decorators: [{
|
|
1263
|
+
type: NgModule,
|
|
1264
|
+
args: [{
|
|
1265
|
+
imports: [HotTableComponent],
|
|
1266
|
+
exports: [HotTableComponent]
|
|
1267
|
+
}]
|
|
1268
|
+
}]
|
|
1269
|
+
});
|
|
1628
1270
|
export { DynamicComponentService, HOT_DESTROYED_WARNING, HOT_GLOBAL_CONFIG, HotCellEditorAdvancedComponent, HotCellEditorComponent, HotCellRendererAdvancedComponent, HotCellRendererComponent, HotGlobalConfigService, HotSettingsResolver, HotTableComponent, HotTableModule, INVALID_ADVANCED_RENDERER_WARNING, INVALID_RENDERER_WARNING, NON_COMMERCIAL_LICENSE, PredefinedTheme, isAdvancedHotCellRendererComponent, isHotCellRendererComponent, isTemplateRef };
|
|
1629
|
-
|
|
1271
|
+
|
|
1272
|
+
//# sourceMappingURL=handsontable-angular-wrapper.mjs.map
|