@angular-bootstrap/ngbootstrap 0.0.11 → 0.0.12
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.
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Input, Directive, EventEmitter, Output, ChangeDetectionStrategy, Component, inject, Injectable, signal, TemplateRef, QueryList, ContentChildren, ContentChild,
|
|
2
|
+
import { Input, Directive, EventEmitter, Output, ChangeDetectionStrategy, Component, inject, Injectable, signal, TemplateRef, Optional, HostListener, ChangeDetectorRef, QueryList, ContentChildren, ContentChild, ViewChild, InjectionToken, Inject, ElementRef, HostBinding, forwardRef, ViewChildren } from '@angular/core';
|
|
3
3
|
import * as i1 from '@angular/common';
|
|
4
4
|
import { CommonModule } from '@angular/common';
|
|
5
5
|
import * as i2 from '@angular/forms';
|
|
@@ -12,10 +12,10 @@ class NgbCellTemplate {
|
|
|
12
12
|
constructor(template) {
|
|
13
13
|
this.template = template;
|
|
14
14
|
}
|
|
15
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.
|
|
16
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.
|
|
15
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbCellTemplate, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
|
|
16
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.9", type: NgbCellTemplate, isStandalone: true, selector: "ng-template[ngbCell]", inputs: { field: ["ngbCell", "field"] }, ngImport: i0 });
|
|
17
17
|
}
|
|
18
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.
|
|
18
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbCellTemplate, decorators: [{
|
|
19
19
|
type: Directive,
|
|
20
20
|
args: [{ selector: 'ng-template[ngbCell]' }]
|
|
21
21
|
}], ctorParameters: () => [{ type: i0.TemplateRef }], propDecorators: { field: [{
|
|
@@ -28,10 +28,10 @@ class NgbEditorTemplate {
|
|
|
28
28
|
constructor(template) {
|
|
29
29
|
this.template = template;
|
|
30
30
|
}
|
|
31
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.
|
|
32
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.
|
|
31
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbEditorTemplate, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
|
|
32
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.9", type: NgbEditorTemplate, isStandalone: true, selector: "ng-template[ngbEditor]", inputs: { field: ["ngbEditor", "field"] }, ngImport: i0 });
|
|
33
33
|
}
|
|
34
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.
|
|
34
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbEditorTemplate, decorators: [{
|
|
35
35
|
type: Directive,
|
|
36
36
|
args: [{ selector: 'ng-template[ngbEditor]' }]
|
|
37
37
|
}], ctorParameters: () => [{ type: i0.TemplateRef }], propDecorators: { field: [{
|
|
@@ -44,10 +44,10 @@ class NgbFilterTemplate {
|
|
|
44
44
|
constructor(template) {
|
|
45
45
|
this.template = template;
|
|
46
46
|
}
|
|
47
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.
|
|
48
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.
|
|
47
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbFilterTemplate, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
|
|
48
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.9", type: NgbFilterTemplate, isStandalone: true, selector: "ng-template[ngbFilter]", inputs: { field: ["ngbFilter", "field"] }, ngImport: i0 });
|
|
49
49
|
}
|
|
50
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.
|
|
50
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbFilterTemplate, decorators: [{
|
|
51
51
|
type: Directive,
|
|
52
52
|
args: [{ selector: 'ng-template[ngbFilter]' }]
|
|
53
53
|
}], ctorParameters: () => [{ type: i0.TemplateRef }], propDecorators: { field: [{
|
|
@@ -59,10 +59,10 @@ class NgbGlobalFilterTemplate {
|
|
|
59
59
|
constructor(template) {
|
|
60
60
|
this.template = template;
|
|
61
61
|
}
|
|
62
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.
|
|
63
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.
|
|
62
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbGlobalFilterTemplate, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
|
|
63
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.9", type: NgbGlobalFilterTemplate, isStandalone: true, selector: "ng-template[ngbGlobalFilter]", ngImport: i0 });
|
|
64
64
|
}
|
|
65
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.
|
|
65
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbGlobalFilterTemplate, decorators: [{
|
|
66
66
|
type: Directive,
|
|
67
67
|
args: [{ selector: 'ng-template[ngbGlobalFilter]' }]
|
|
68
68
|
}], ctorParameters: () => [{ type: i0.TemplateRef }] });
|
|
@@ -71,10 +71,10 @@ class NgbRowDetailTemplate {
|
|
|
71
71
|
constructor(template) {
|
|
72
72
|
this.template = template;
|
|
73
73
|
}
|
|
74
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.
|
|
75
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.
|
|
74
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbRowDetailTemplate, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
|
|
75
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.9", type: NgbRowDetailTemplate, isStandalone: true, selector: "ng-template[ngbRowDetail]", ngImport: i0 });
|
|
76
76
|
}
|
|
77
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.
|
|
77
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbRowDetailTemplate, decorators: [{
|
|
78
78
|
type: Directive,
|
|
79
79
|
args: [{ selector: 'ng-template[ngbRowDetail]' }]
|
|
80
80
|
}], ctorParameters: () => [{ type: i0.TemplateRef }] });
|
|
@@ -114,8 +114,8 @@ class NgbPaginationComponent {
|
|
|
114
114
|
return;
|
|
115
115
|
this.pageChange.emit(p);
|
|
116
116
|
}
|
|
117
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.
|
|
118
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.
|
|
117
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbPaginationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
118
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.9", type: NgbPaginationComponent, isStandalone: true, selector: "ngb-pagination", inputs: { page: "page", pageSize: "pageSize", collectionSize: "collectionSize", maxSize: "maxSize" }, outputs: { pageChange: "pageChange" }, ngImport: i0, template: `
|
|
119
119
|
<nav *ngIf="totalPages >= 1" aria-label="Pagination">
|
|
120
120
|
<ul class="pagination pagination-sm justify-content-center mb-0">
|
|
121
121
|
<li class="page-item" [class.disabled]="page === 1">
|
|
@@ -134,7 +134,7 @@ class NgbPaginationComponent {
|
|
|
134
134
|
</nav>
|
|
135
135
|
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
136
136
|
}
|
|
137
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.
|
|
137
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbPaginationComponent, decorators: [{
|
|
138
138
|
type: Component,
|
|
139
139
|
args: [{
|
|
140
140
|
selector: 'ngb-pagination',
|
|
@@ -190,10 +190,10 @@ class NgbExportService {
|
|
|
190
190
|
throw new Error('No ExcelExportAdapter provided');
|
|
191
191
|
return this.excel.export(p);
|
|
192
192
|
}
|
|
193
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.
|
|
194
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.
|
|
193
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbExportService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
194
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbExportService, providedIn: 'root' });
|
|
195
195
|
}
|
|
196
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.
|
|
196
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbExportService, decorators: [{
|
|
197
197
|
type: Injectable,
|
|
198
198
|
args: [{ providedIn: 'root' }]
|
|
199
199
|
}] });
|
|
@@ -323,14 +323,247 @@ class XlsxAdapter {
|
|
|
323
323
|
class ExportButtonDirective {
|
|
324
324
|
// Expose the TemplateRef so the grid can render it with a context
|
|
325
325
|
templateRef = inject(TemplateRef);
|
|
326
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.
|
|
327
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.
|
|
326
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ExportButtonDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
327
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.9", type: ExportButtonDirective, isStandalone: true, selector: "[ngbExportButton]", ngImport: i0 });
|
|
328
328
|
}
|
|
329
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.
|
|
329
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ExportButtonDirective, decorators: [{
|
|
330
330
|
type: Directive,
|
|
331
331
|
args: [{ selector: '[ngbExportButton]' }]
|
|
332
332
|
}] });
|
|
333
333
|
|
|
334
|
+
class NgbGridHighlightDirective {
|
|
335
|
+
grid;
|
|
336
|
+
rowKey;
|
|
337
|
+
highlightColumnIndex;
|
|
338
|
+
highlightedIndex = [];
|
|
339
|
+
constructor(grid) {
|
|
340
|
+
this.grid = grid;
|
|
341
|
+
}
|
|
342
|
+
ngOnInit() {
|
|
343
|
+
this.apply();
|
|
344
|
+
}
|
|
345
|
+
ngOnChanges(_ch) {
|
|
346
|
+
this.apply();
|
|
347
|
+
}
|
|
348
|
+
apply() {
|
|
349
|
+
if (!this.grid)
|
|
350
|
+
return;
|
|
351
|
+
this.grid.highlightRowKey = this.rowKey;
|
|
352
|
+
this.grid.highlightColKey = this.highlightColumnIndex;
|
|
353
|
+
this.grid.highlightedIndex = this.highlightedIndex ?? [];
|
|
354
|
+
this.grid.updateHighlightCache();
|
|
355
|
+
}
|
|
356
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbGridHighlightDirective, deps: [{ token: Datagrid, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
|
|
357
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.9", type: NgbGridHighlightDirective, isStandalone: true, selector: "[ngbGridHighlight]", inputs: { rowKey: ["ngbGridHighlight", "rowKey"], highlightColumnIndex: "highlightColumnIndex", highlightedIndex: "highlightedIndex" }, usesOnChanges: true, ngImport: i0 });
|
|
358
|
+
}
|
|
359
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbGridHighlightDirective, decorators: [{
|
|
360
|
+
type: Directive,
|
|
361
|
+
args: [{
|
|
362
|
+
selector: '[ngbGridHighlight]',
|
|
363
|
+
standalone: true
|
|
364
|
+
}]
|
|
365
|
+
}], ctorParameters: () => [{ type: Datagrid, decorators: [{
|
|
366
|
+
type: Optional
|
|
367
|
+
}] }], propDecorators: { rowKey: [{
|
|
368
|
+
type: Input,
|
|
369
|
+
args: ['ngbGridHighlight']
|
|
370
|
+
}], highlightColumnIndex: [{
|
|
371
|
+
type: Input
|
|
372
|
+
}], highlightedIndex: [{
|
|
373
|
+
type: Input
|
|
374
|
+
}] } });
|
|
375
|
+
|
|
376
|
+
const MIN_WIDTH = 40;
|
|
377
|
+
const MAX_WIDTH = 320;
|
|
378
|
+
const MAX_SAMPLE_ROWS = 50;
|
|
379
|
+
const CHAR_WIDTH_FACTOR = 0.6;
|
|
380
|
+
class NgbSyncColgroupDirective {
|
|
381
|
+
el;
|
|
382
|
+
syncId;
|
|
383
|
+
syncRole = 'header';
|
|
384
|
+
static registry = new Map();
|
|
385
|
+
mutationObserver;
|
|
386
|
+
resizeObserver;
|
|
387
|
+
rafId = null;
|
|
388
|
+
constructor(el) {
|
|
389
|
+
this.el = el;
|
|
390
|
+
}
|
|
391
|
+
ngAfterViewInit() {
|
|
392
|
+
if (!this.syncId)
|
|
393
|
+
return;
|
|
394
|
+
const entry = this.ensureEntry();
|
|
395
|
+
if (this.syncRole === 'header') {
|
|
396
|
+
entry.header = this;
|
|
397
|
+
this.measureAndDistribute();
|
|
398
|
+
}
|
|
399
|
+
else {
|
|
400
|
+
entry.bodies.add(this);
|
|
401
|
+
if (entry.header)
|
|
402
|
+
entry.header.measureAndDistribute();
|
|
403
|
+
if (entry.widths?.length)
|
|
404
|
+
this.apply(entry.widths);
|
|
405
|
+
this.startObservers();
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
ngOnDestroy() {
|
|
409
|
+
if (!this.syncId)
|
|
410
|
+
return;
|
|
411
|
+
if (this.rafId != null)
|
|
412
|
+
cancelAnimationFrame(this.rafId);
|
|
413
|
+
this.mutationObserver?.disconnect();
|
|
414
|
+
this.resizeObserver?.disconnect();
|
|
415
|
+
const entry = NgbSyncColgroupDirective.registry.get(this.syncId);
|
|
416
|
+
if (!entry)
|
|
417
|
+
return;
|
|
418
|
+
if (entry.header === this)
|
|
419
|
+
entry.header = undefined;
|
|
420
|
+
entry.bodies.delete(this);
|
|
421
|
+
if (!entry.header && entry.bodies.size === 0) {
|
|
422
|
+
NgbSyncColgroupDirective.registry.delete(this.syncId);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
onResize() {
|
|
426
|
+
if (this.syncRole === 'header')
|
|
427
|
+
this.measureAndDistribute();
|
|
428
|
+
}
|
|
429
|
+
measureAndDistribute() {
|
|
430
|
+
const widths = this.measure();
|
|
431
|
+
if (!widths.length)
|
|
432
|
+
return;
|
|
433
|
+
const entry = this.ensureEntry();
|
|
434
|
+
entry.widths = widths;
|
|
435
|
+
this.apply(widths);
|
|
436
|
+
entry.bodies.forEach(b => b.apply(widths));
|
|
437
|
+
}
|
|
438
|
+
ensureEntry() {
|
|
439
|
+
let entry = NgbSyncColgroupDirective.registry.get(this.syncId);
|
|
440
|
+
if (!entry) {
|
|
441
|
+
entry = { bodies: new Set() };
|
|
442
|
+
NgbSyncColgroupDirective.registry.set(this.syncId, entry);
|
|
443
|
+
}
|
|
444
|
+
return entry;
|
|
445
|
+
}
|
|
446
|
+
startObservers() {
|
|
447
|
+
const bodyTable = this.tableEl();
|
|
448
|
+
const tbody = bodyTable?.querySelector('tbody');
|
|
449
|
+
if (tbody && typeof MutationObserver !== 'undefined') {
|
|
450
|
+
this.mutationObserver = new MutationObserver(() => this.scheduleMeasure());
|
|
451
|
+
this.mutationObserver.observe(tbody, { childList: true, subtree: true, characterData: true });
|
|
452
|
+
}
|
|
453
|
+
if (bodyTable && typeof ResizeObserver !== 'undefined') {
|
|
454
|
+
this.resizeObserver = new ResizeObserver(() => this.scheduleMeasure());
|
|
455
|
+
this.resizeObserver.observe(bodyTable);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
scheduleMeasure() {
|
|
459
|
+
if (this.rafId != null)
|
|
460
|
+
return;
|
|
461
|
+
this.rafId = requestAnimationFrame(() => {
|
|
462
|
+
this.rafId = null;
|
|
463
|
+
const entry = NgbSyncColgroupDirective.registry.get(this.syncId);
|
|
464
|
+
entry?.header?.measureAndDistribute();
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
colElements() {
|
|
468
|
+
return Array.from(this.el.nativeElement.querySelectorAll('col'));
|
|
469
|
+
}
|
|
470
|
+
tableEl() {
|
|
471
|
+
return this.el.nativeElement.closest('table');
|
|
472
|
+
}
|
|
473
|
+
firstBodyForSync() {
|
|
474
|
+
const entry = NgbSyncColgroupDirective.registry.get(this.syncId);
|
|
475
|
+
const bodyDir = this.syncRole === 'body'
|
|
476
|
+
? this
|
|
477
|
+
: entry ? Array.from(entry.bodies.values())[0] : undefined;
|
|
478
|
+
return bodyDir?.tableEl() ?? null;
|
|
479
|
+
}
|
|
480
|
+
measure() {
|
|
481
|
+
const bodyTable = this.firstBodyForSync();
|
|
482
|
+
const cols = this.colElements();
|
|
483
|
+
if (!cols.length)
|
|
484
|
+
return [];
|
|
485
|
+
if (!bodyTable) {
|
|
486
|
+
const entry = NgbSyncColgroupDirective.registry.get(this.syncId);
|
|
487
|
+
return entry?.widths ?? [];
|
|
488
|
+
}
|
|
489
|
+
const bodyRows = Array.from(bodyTable.querySelectorAll('tbody tr')).slice(0, MAX_SAMPLE_ROWS);
|
|
490
|
+
return cols.map((_col, colIndex) => {
|
|
491
|
+
let maxContent = 0;
|
|
492
|
+
for (const tr of bodyRows) {
|
|
493
|
+
const td = tr.querySelectorAll('td')[colIndex];
|
|
494
|
+
if (!td)
|
|
495
|
+
continue;
|
|
496
|
+
maxContent = Math.max(maxContent, this.measureCellContent(td));
|
|
497
|
+
if (maxContent >= MAX_WIDTH)
|
|
498
|
+
break;
|
|
499
|
+
}
|
|
500
|
+
if (maxContent === 0)
|
|
501
|
+
maxContent = MIN_WIDTH;
|
|
502
|
+
return Math.min(Math.max(maxContent, MIN_WIDTH), MAX_WIDTH);
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
apply(widths) {
|
|
506
|
+
const cols = this.colElements();
|
|
507
|
+
widths.forEach((w, i) => {
|
|
508
|
+
const col = cols[i];
|
|
509
|
+
if (!col)
|
|
510
|
+
return;
|
|
511
|
+
col.style.width = w ? `${w}px` : '';
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
measureCellContent(cell) {
|
|
515
|
+
const style = getComputedStyle(cell);
|
|
516
|
+
const chrome = (parseFloat(style.paddingLeft) || 0) +
|
|
517
|
+
(parseFloat(style.paddingRight) || 0) +
|
|
518
|
+
(parseFloat(style.borderLeftWidth) || 0) +
|
|
519
|
+
(parseFloat(style.borderRightWidth) || 0);
|
|
520
|
+
const interactive = cell.querySelector('input, select, textarea, button');
|
|
521
|
+
if (interactive)
|
|
522
|
+
return (interactive.getBoundingClientRect().width || 0) + chrome;
|
|
523
|
+
const text = (cell.textContent ?? '').trim();
|
|
524
|
+
const fontSize = parseFloat(style.fontSize) || 14;
|
|
525
|
+
const font = style.font || `${style.fontStyle} ${style.fontVariant} ${style.fontWeight} ${style.fontSize} / ${style.lineHeight} ${style.fontFamily}`;
|
|
526
|
+
let contentWidth = 0;
|
|
527
|
+
const isJsdom = typeof navigator !== 'undefined' && /jsdom/i.test(navigator.userAgent);
|
|
528
|
+
const canvas = !isJsdom && typeof document !== 'undefined' ? document.createElement('canvas') : null;
|
|
529
|
+
let ctx = null;
|
|
530
|
+
if (canvas?.getContext) {
|
|
531
|
+
try {
|
|
532
|
+
ctx = canvas.getContext('2d');
|
|
533
|
+
}
|
|
534
|
+
catch {
|
|
535
|
+
ctx = null;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
if (ctx && font) {
|
|
539
|
+
ctx.font = font;
|
|
540
|
+
const metrics = ctx.measureText(text);
|
|
541
|
+
contentWidth = metrics?.width ?? 0;
|
|
542
|
+
}
|
|
543
|
+
if (!contentWidth) {
|
|
544
|
+
contentWidth = text.length * (fontSize * CHAR_WIDTH_FACTOR);
|
|
545
|
+
}
|
|
546
|
+
return Math.ceil(contentWidth + chrome);
|
|
547
|
+
}
|
|
548
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbSyncColgroupDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
|
|
549
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.9", type: NgbSyncColgroupDirective, isStandalone: true, selector: "[ngbSyncColgroup]", inputs: { syncId: ["ngbSyncColgroup", "syncId"], syncRole: "syncRole" }, host: { listeners: { "window:resize": "onResize()" } }, ngImport: i0 });
|
|
550
|
+
}
|
|
551
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbSyncColgroupDirective, decorators: [{
|
|
552
|
+
type: Directive,
|
|
553
|
+
args: [{
|
|
554
|
+
selector: '[ngbSyncColgroup]',
|
|
555
|
+
standalone: true
|
|
556
|
+
}]
|
|
557
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { syncId: [{
|
|
558
|
+
type: Input,
|
|
559
|
+
args: ['ngbSyncColgroup']
|
|
560
|
+
}], syncRole: [{
|
|
561
|
+
type: Input
|
|
562
|
+
}], onResize: [{
|
|
563
|
+
type: HostListener,
|
|
564
|
+
args: ['window:resize']
|
|
565
|
+
}] } });
|
|
566
|
+
|
|
334
567
|
const MAX_EMAIL_LENGTH = 254;
|
|
335
568
|
const isReasonableEmail = (value) => {
|
|
336
569
|
if (value == null)
|
|
@@ -372,6 +605,41 @@ class Datagrid {
|
|
|
372
605
|
addButtonAriaLabel = 'Add row';
|
|
373
606
|
/** Visible text rendered inside the add-row button. */
|
|
374
607
|
addButtonText = '+ Add';
|
|
608
|
+
/** Shows sticky toggle column and keeps pinned rows at the top of the list. */
|
|
609
|
+
stickyRows = false;
|
|
610
|
+
/** Enables sticky column header when scrolling. */
|
|
611
|
+
stickyHeader = false;
|
|
612
|
+
/** Enables sticky footer when scrolling. */
|
|
613
|
+
stickyFooter = false;
|
|
614
|
+
/** Enables scroll container (used when pagination is off). */
|
|
615
|
+
scrollable = true;
|
|
616
|
+
/** Row height used to stack multiple sticky rows without overlap (px). */
|
|
617
|
+
stickyRowHeight = 40;
|
|
618
|
+
/** Header height (px) used to offset sticky rows below the header. */
|
|
619
|
+
stickyHeaderHeight = 40;
|
|
620
|
+
/** Footer height (px) used to offset scrollable area. */
|
|
621
|
+
stickyFooterHeight = 56;
|
|
622
|
+
/** Bootstrap-like table styling options. */
|
|
623
|
+
tableOptions = {};
|
|
624
|
+
/** Selection mode for rows. */
|
|
625
|
+
selectionMode = 'none';
|
|
626
|
+
/** Selection activation: row click, checkbox only, or both. */
|
|
627
|
+
selectionBehavior = 'row';
|
|
628
|
+
/** Keyboard modifier rules for multi-select. */
|
|
629
|
+
selectionKeyMode = 'desktop';
|
|
630
|
+
/** Enable header select-all checkbox for multiple mode. */
|
|
631
|
+
selectAllEnabled = true;
|
|
632
|
+
/** A11y labels for selection controls. */
|
|
633
|
+
selectionA11yLabels = {};
|
|
634
|
+
/** Disable selection for specific rows. */
|
|
635
|
+
selectionDisabledFn;
|
|
636
|
+
/** Highlight items (row/cell). */
|
|
637
|
+
highlightedIndex = [];
|
|
638
|
+
/** Row key for highlighting. */
|
|
639
|
+
highlightRowKey = null;
|
|
640
|
+
/** Column key for highlighting. */
|
|
641
|
+
highlightColKey = null;
|
|
642
|
+
scrollbarWidth = 0;
|
|
375
643
|
/** Accessible label for the global filter input. */
|
|
376
644
|
globalFilterAriaLabel = 'Search all columns';
|
|
377
645
|
/** Accessible label announced when expanding a row. */
|
|
@@ -402,6 +670,9 @@ class Datagrid {
|
|
|
402
670
|
dataProviderSelection; // used when pages='selection'
|
|
403
671
|
// Grab the directive and its TemplateRef
|
|
404
672
|
exportButtonDir;
|
|
673
|
+
bodyScroller;
|
|
674
|
+
headerScroller;
|
|
675
|
+
colgroupSyncId = `dg-col-${Math.random().toString(36).slice(2, 8)}`;
|
|
405
676
|
exporting = false;
|
|
406
677
|
rowAdd = new EventEmitter();
|
|
407
678
|
// events
|
|
@@ -412,6 +683,7 @@ class Datagrid {
|
|
|
412
683
|
sortChange = new EventEmitter();
|
|
413
684
|
filtersChange = new EventEmitter();
|
|
414
685
|
pageChange = new EventEmitter();
|
|
686
|
+
selectionChange = new EventEmitter();
|
|
415
687
|
rowDetailTpl;
|
|
416
688
|
exporter = inject(NgbExportService); // instead of constructor(private exporter: NgbExportService) {}
|
|
417
689
|
expanded = new Set();
|
|
@@ -423,6 +695,10 @@ class Datagrid {
|
|
|
423
695
|
errorsNew = {};
|
|
424
696
|
// --- sorting (from previous step)
|
|
425
697
|
sort = { active: null, direction: '' };
|
|
698
|
+
stickyRowIds = new Set();
|
|
699
|
+
selectedRowIds = new Set();
|
|
700
|
+
selectionAnchor = null;
|
|
701
|
+
highlightRowMap = new Map();
|
|
426
702
|
// --- filtering
|
|
427
703
|
globalFilter = '';
|
|
428
704
|
filters = {}; // per-column text
|
|
@@ -436,6 +712,7 @@ class Datagrid {
|
|
|
436
712
|
saveAttemptedNew = false;
|
|
437
713
|
addDraftRowId = null;
|
|
438
714
|
defaultEditService = new NgbDatagridDefaultEditService();
|
|
715
|
+
cdr = inject(ChangeDetectorRef);
|
|
439
716
|
norm(v) {
|
|
440
717
|
return (v ?? '').toString().toLowerCase().trim();
|
|
441
718
|
}
|
|
@@ -538,19 +815,22 @@ class Datagrid {
|
|
|
538
815
|
});
|
|
539
816
|
}
|
|
540
817
|
get sorted() {
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
818
|
+
const base = (!this.enableSorting || !this.sort.active || !this.sort.direction)
|
|
819
|
+
? [...this.filtered]
|
|
820
|
+
: (() => {
|
|
821
|
+
const copy = [...this.filtered];
|
|
822
|
+
const { active, direction } = this.sort;
|
|
823
|
+
copy.sort((a, b) => {
|
|
824
|
+
const av = a?.[active];
|
|
825
|
+
const bv = b?.[active];
|
|
826
|
+
const cmp = typeof av === 'string' && typeof bv === 'string'
|
|
827
|
+
? av.localeCompare(bv, undefined, { numeric: true, sensitivity: 'base' })
|
|
828
|
+
: av < bv ? -1 : av > bv ? 1 : 0;
|
|
829
|
+
return direction === 'asc' ? cmp : -cmp;
|
|
830
|
+
});
|
|
831
|
+
return copy;
|
|
832
|
+
})();
|
|
833
|
+
return this.withStickyRowsFirst(base);
|
|
554
834
|
}
|
|
555
835
|
// pagination (filled in next step)
|
|
556
836
|
get paged() {
|
|
@@ -565,10 +845,61 @@ class Datagrid {
|
|
|
565
845
|
}
|
|
566
846
|
get startIndex() { const total = this.sorted.length; return total ? (this.page - 1) * this.pageSize + 1 : 0; }
|
|
567
847
|
get endIndex() { return Math.min(this.page * this.pageSize, this.sorted.length); }
|
|
848
|
+
get shouldEnableScroll() {
|
|
849
|
+
return this.scrollable;
|
|
850
|
+
}
|
|
851
|
+
get isHeaderSticky() {
|
|
852
|
+
return this.stickyHeaderEnabled && this.shouldEnableScroll;
|
|
853
|
+
}
|
|
854
|
+
get isFooterSticky() {
|
|
855
|
+
return this.stickyFooterEnabled && this.shouldEnableScroll;
|
|
856
|
+
}
|
|
568
857
|
get detailColspan() {
|
|
569
858
|
const actionCols = (this.enableEdit || this.enableDelete) ? 1 : 0;
|
|
570
859
|
const caretCol = this.rowDetailTpl ? 1 : 0;
|
|
571
|
-
|
|
860
|
+
const stickyCol = this.stickyRowsEnabled ? 1 : 0;
|
|
861
|
+
const selectionCol = this.isSelectionEnabled() ? 1 : 0;
|
|
862
|
+
return this.columns.length + actionCols + caretCol + stickyCol + selectionCol;
|
|
863
|
+
}
|
|
864
|
+
get tableClassList() {
|
|
865
|
+
const opts = this.tableOptions || {};
|
|
866
|
+
const cls = ['table'];
|
|
867
|
+
if (opts.stripedRows)
|
|
868
|
+
cls.push('table-striped');
|
|
869
|
+
if (opts.stripedColumns)
|
|
870
|
+
cls.push('table-striped-columns');
|
|
871
|
+
if (opts.hoverRows)
|
|
872
|
+
cls.push('table-hover');
|
|
873
|
+
if (opts.bordered)
|
|
874
|
+
cls.push('table-bordered');
|
|
875
|
+
if (opts.borderless)
|
|
876
|
+
cls.push('table-borderless');
|
|
877
|
+
if (opts.small)
|
|
878
|
+
cls.push('table-sm');
|
|
879
|
+
if (opts.groupDividers)
|
|
880
|
+
cls.push('table-group-divider');
|
|
881
|
+
if (opts.align === 'middle')
|
|
882
|
+
cls.push('align-middle');
|
|
883
|
+
if (opts.align === 'bottom')
|
|
884
|
+
cls.push('align-bottom');
|
|
885
|
+
return cls;
|
|
886
|
+
}
|
|
887
|
+
get responsiveWrapperClasses() {
|
|
888
|
+
const r = this.tableOptions?.responsive;
|
|
889
|
+
if (r === false)
|
|
890
|
+
return [];
|
|
891
|
+
if (r === true || r === undefined)
|
|
892
|
+
return ['table-responsive'];
|
|
893
|
+
return [`table-responsive-${r}`];
|
|
894
|
+
}
|
|
895
|
+
updateHighlightCache() {
|
|
896
|
+
this.highlightRowMap.clear();
|
|
897
|
+
(this.highlightedIndex || []).forEach(item => {
|
|
898
|
+
const rowKey = item.row;
|
|
899
|
+
if (!this.highlightRowMap.has(rowKey))
|
|
900
|
+
this.highlightRowMap.set(rowKey, []);
|
|
901
|
+
this.highlightRowMap.get(rowKey)?.push(item);
|
|
902
|
+
});
|
|
572
903
|
}
|
|
573
904
|
headerText(col) {
|
|
574
905
|
return (col.header ?? col.field ?? '').toString();
|
|
@@ -599,6 +930,18 @@ class Datagrid {
|
|
|
599
930
|
exportAriaLabel(kind) {
|
|
600
931
|
return kind === 'pdf' ? this.exportPdfAriaLabel : this.exportExcelAriaLabel;
|
|
601
932
|
}
|
|
933
|
+
withStickyRowsFirst(rows) {
|
|
934
|
+
if (!this.stickyRows || this.stickyRowIds.size === 0)
|
|
935
|
+
return rows;
|
|
936
|
+
const sticky = [];
|
|
937
|
+
const rest = [];
|
|
938
|
+
rows.forEach(r => {
|
|
939
|
+
const di = this.data.indexOf(r);
|
|
940
|
+
const id = this.getRowId(di >= 0 ? di : 0, r);
|
|
941
|
+
(this.stickyRowIds.has(id) ? sticky : rest).push(r);
|
|
942
|
+
});
|
|
943
|
+
return [...sticky, ...rest];
|
|
944
|
+
}
|
|
602
945
|
// Helpers to map from paged index → original data index
|
|
603
946
|
// helper used above
|
|
604
947
|
dataIndexFromPaged(i) {
|
|
@@ -694,9 +1037,14 @@ class Datagrid {
|
|
|
694
1037
|
this.filterTplQ?.changes.subscribe(rebuild);
|
|
695
1038
|
this.globalTplQ?.changes.subscribe(rebuild);
|
|
696
1039
|
}
|
|
1040
|
+
ngAfterViewInit() {
|
|
1041
|
+
queueMicrotask(() => this.syncScrollbarWidth());
|
|
1042
|
+
}
|
|
697
1043
|
ngOnChanges(ch) {
|
|
698
1044
|
if (ch['columns'])
|
|
699
1045
|
this.rebuildFilterForm();
|
|
1046
|
+
if (ch['highlightedIndex'])
|
|
1047
|
+
this.updateHighlightCache();
|
|
700
1048
|
}
|
|
701
1049
|
getRowId(rowIndex, row) {
|
|
702
1050
|
return this.trackBy ? this.trackBy(rowIndex, row) : rowIndex;
|
|
@@ -841,6 +1189,32 @@ class Datagrid {
|
|
|
841
1189
|
const rowIndex = di >= 0 ? di : index;
|
|
842
1190
|
return this.trackBy ? this.trackBy(rowIndex, row) : rowIndex;
|
|
843
1191
|
};
|
|
1192
|
+
rowKeyValue(row, rowIndex) {
|
|
1193
|
+
const key = this.highlightRowKey;
|
|
1194
|
+
if (typeof key === 'function')
|
|
1195
|
+
return key(row, rowIndex);
|
|
1196
|
+
if (typeof key === 'string')
|
|
1197
|
+
return row?.[key];
|
|
1198
|
+
return rowIndex;
|
|
1199
|
+
}
|
|
1200
|
+
colKeyValue(column, colIndex) {
|
|
1201
|
+
const key = this.highlightColKey;
|
|
1202
|
+
if (typeof key === 'function')
|
|
1203
|
+
return key(column, colIndex);
|
|
1204
|
+
if (typeof key === 'string')
|
|
1205
|
+
return column?.[key];
|
|
1206
|
+
return colIndex;
|
|
1207
|
+
}
|
|
1208
|
+
isRowHighlighted(row, rowIndex) {
|
|
1209
|
+
const key = this.rowKeyValue(row, rowIndex);
|
|
1210
|
+
return this.highlightRowMap.has(key) && this.highlightRowMap.get(key)?.some(h => h.columnKey === undefined) === true;
|
|
1211
|
+
}
|
|
1212
|
+
isCellHighlighted(row, rowIndex, column, colIndex) {
|
|
1213
|
+
const key = this.rowKeyValue(row, rowIndex);
|
|
1214
|
+
const colKey = this.colKeyValue(column, colIndex);
|
|
1215
|
+
const items = this.highlightRowMap.get(key);
|
|
1216
|
+
return !!items?.some(h => h.columnKey === colKey);
|
|
1217
|
+
}
|
|
844
1218
|
toggleSort(field) {
|
|
845
1219
|
if (!this.enableSorting)
|
|
846
1220
|
return;
|
|
@@ -920,18 +1294,198 @@ class Datagrid {
|
|
|
920
1294
|
const r = this.responsive;
|
|
921
1295
|
return r === true || (!!r && r.enabled === true);
|
|
922
1296
|
}
|
|
923
|
-
|
|
924
|
-
|
|
1297
|
+
isRowSticky(row, pagedIndex) {
|
|
1298
|
+
if (!this.stickyRows)
|
|
1299
|
+
return false;
|
|
1300
|
+
const di = this.data.indexOf(row);
|
|
1301
|
+
const id = this.getRowId(di >= 0 ? di : pagedIndex, row);
|
|
1302
|
+
return this.stickyRowIds.has(id);
|
|
1303
|
+
}
|
|
1304
|
+
toggleStickyRow(pagedIndex) {
|
|
1305
|
+
if (!this.stickyRows)
|
|
1306
|
+
return;
|
|
1307
|
+
const row = this.paged[pagedIndex];
|
|
1308
|
+
if (!row)
|
|
1309
|
+
return;
|
|
1310
|
+
const di = this.data.indexOf(row);
|
|
1311
|
+
const id = this.getRowId(di >= 0 ? di : pagedIndex, row);
|
|
1312
|
+
if (this.stickyRowIds.has(id))
|
|
1313
|
+
this.stickyRowIds.delete(id);
|
|
1314
|
+
else
|
|
1315
|
+
this.stickyRowIds.add(id);
|
|
1316
|
+
}
|
|
1317
|
+
stickyIcon(row, pagedIndex) {
|
|
1318
|
+
return this.isRowSticky(row, pagedIndex) ? 'pin-angle-fill' : 'pin-fill';
|
|
1319
|
+
}
|
|
1320
|
+
stickyTop(row, pagedIndex) {
|
|
1321
|
+
if (!this.isRowSticky(row, pagedIndex))
|
|
1322
|
+
return null;
|
|
1323
|
+
const stickyBefore = this.paged
|
|
1324
|
+
.slice(0, pagedIndex)
|
|
1325
|
+
.filter((r, idx) => this.isRowSticky(r, idx)).length;
|
|
1326
|
+
return stickyBefore * this.stickyRowHeight;
|
|
1327
|
+
}
|
|
1328
|
+
// Selection helpers
|
|
1329
|
+
get stickyRowsEnabled() {
|
|
1330
|
+
return this.tableOptions?.stickyRows ?? this.stickyRows;
|
|
1331
|
+
}
|
|
1332
|
+
get stickyHeaderEnabled() {
|
|
1333
|
+
return this.tableOptions?.stickyHeader ?? this.stickyHeader;
|
|
1334
|
+
}
|
|
1335
|
+
get stickyFooterEnabled() {
|
|
1336
|
+
return this.tableOptions?.stickyFooter ?? this.stickyFooter;
|
|
1337
|
+
}
|
|
1338
|
+
isSelectionEnabled() {
|
|
1339
|
+
return this.selectionMode !== 'none';
|
|
1340
|
+
}
|
|
1341
|
+
isCheckboxOnly() {
|
|
1342
|
+
return this.selectionBehavior === 'checkbox';
|
|
1343
|
+
}
|
|
1344
|
+
isSelectionDisabled(row, pagedIndex) {
|
|
1345
|
+
if (!this.selectionDisabledFn)
|
|
1346
|
+
return false;
|
|
1347
|
+
const di = this.data.indexOf(this.paged[pagedIndex]);
|
|
1348
|
+
return this.selectionDisabledFn(row, di >= 0 ? di : pagedIndex);
|
|
1349
|
+
}
|
|
1350
|
+
isRowSelected(row, pagedIndex) {
|
|
1351
|
+
const di = this.data.indexOf(this.paged[pagedIndex]);
|
|
1352
|
+
const id = this.getRowId(di >= 0 ? di : pagedIndex, row);
|
|
1353
|
+
return this.selectedRowIds.has(id);
|
|
1354
|
+
}
|
|
1355
|
+
toggleSelection(pagedIndex, event) {
|
|
1356
|
+
if (!this.isSelectionEnabled())
|
|
1357
|
+
return;
|
|
1358
|
+
const row = this.paged[pagedIndex];
|
|
1359
|
+
if (!row || this.isSelectionDisabled(row, pagedIndex))
|
|
1360
|
+
return;
|
|
1361
|
+
const di = this.data.indexOf(row);
|
|
1362
|
+
const id = this.getRowId(di >= 0 ? di : pagedIndex, row);
|
|
1363
|
+
const currentlySelected = this.selectedRowIds.has(id);
|
|
1364
|
+
const isMulti = this.selectionMode === 'multiple';
|
|
1365
|
+
const desktop = this.selectionKeyMode === 'desktop';
|
|
1366
|
+
const shift = desktop && !!(event && 'shiftKey' in event && event.shiftKey);
|
|
1367
|
+
const meta = desktop && !!(event && (('metaKey' in event && event.metaKey) || ('ctrlKey' in event && event.ctrlKey)));
|
|
1368
|
+
if (!isMulti) {
|
|
1369
|
+
this.selectedRowIds.clear();
|
|
1370
|
+
this.selectedRowIds.add(id);
|
|
1371
|
+
this.selectionAnchor = pagedIndex;
|
|
1372
|
+
this.emitSelection(row, di, true);
|
|
1373
|
+
return;
|
|
1374
|
+
}
|
|
1375
|
+
if (shift && this.selectionAnchor != null) {
|
|
1376
|
+
const start = Math.min(this.selectionAnchor, pagedIndex);
|
|
1377
|
+
const end = Math.max(this.selectionAnchor, pagedIndex);
|
|
1378
|
+
this.selectedRowIds.clear();
|
|
1379
|
+
for (let i = start; i <= end; i++) {
|
|
1380
|
+
const r = this.paged[i];
|
|
1381
|
+
if (!r || this.isSelectionDisabled(r, i))
|
|
1382
|
+
continue;
|
|
1383
|
+
const rid = this.getRowId(this.data.indexOf(r), r);
|
|
1384
|
+
this.selectedRowIds.add(rid);
|
|
1385
|
+
}
|
|
1386
|
+
this.emitSelection(row, di, true);
|
|
1387
|
+
return;
|
|
1388
|
+
}
|
|
1389
|
+
if (meta || !desktop) {
|
|
1390
|
+
if (currentlySelected)
|
|
1391
|
+
this.selectedRowIds.delete(id);
|
|
1392
|
+
else
|
|
1393
|
+
this.selectedRowIds.add(id);
|
|
1394
|
+
}
|
|
1395
|
+
else {
|
|
1396
|
+
this.selectedRowIds.clear();
|
|
1397
|
+
this.selectedRowIds.add(id);
|
|
1398
|
+
}
|
|
1399
|
+
this.selectionAnchor = pagedIndex;
|
|
1400
|
+
this.emitSelection(row, di, !currentlySelected || (!meta && desktop));
|
|
1401
|
+
}
|
|
1402
|
+
emitSelection(row, dataIndex, selected) {
|
|
1403
|
+
this.selectionChange.emit({
|
|
1404
|
+
selected: this.data.filter((r, idx) => this.selectedRowIds.has(this.getRowId(idx, r))),
|
|
1405
|
+
lastAction: { row, index: dataIndex, selected }
|
|
1406
|
+
});
|
|
1407
|
+
}
|
|
1408
|
+
toggleSelectAllCurrentPage() {
|
|
1409
|
+
if (this.selectionMode !== 'multiple' || !this.selectAllEnabled)
|
|
1410
|
+
return;
|
|
1411
|
+
const allSelectable = this.paged.filter((r, i) => !this.isSelectionDisabled(r, i));
|
|
1412
|
+
const allSelected = allSelectable.every((r, i) => this.isRowSelected(r, i));
|
|
1413
|
+
if (allSelected) {
|
|
1414
|
+
allSelectable.forEach((r, i) => {
|
|
1415
|
+
const rid = this.getRowId(this.data.indexOf(r), r);
|
|
1416
|
+
this.selectedRowIds.delete(rid);
|
|
1417
|
+
});
|
|
1418
|
+
}
|
|
1419
|
+
else {
|
|
1420
|
+
allSelectable.forEach((r, i) => {
|
|
1421
|
+
const rid = this.getRowId(this.data.indexOf(r), r);
|
|
1422
|
+
this.selectedRowIds.add(rid);
|
|
1423
|
+
});
|
|
1424
|
+
}
|
|
1425
|
+
this.selectionChange.emit({
|
|
1426
|
+
selected: this.data.filter((r, idx) => this.selectedRowIds.has(this.getRowId(idx, r))),
|
|
1427
|
+
lastAction: null
|
|
1428
|
+
});
|
|
1429
|
+
}
|
|
1430
|
+
isPageAllSelected() {
|
|
1431
|
+
const selectable = this.paged.filter((r, i) => !this.isSelectionDisabled(r, i));
|
|
1432
|
+
return selectable.length > 0 && selectable.every((r, i) => this.isRowSelected(r, i));
|
|
1433
|
+
}
|
|
1434
|
+
isPageIndeterminate() {
|
|
1435
|
+
const selectable = this.paged.filter((r, i) => !this.isSelectionDisabled(r, i));
|
|
1436
|
+
const selectedCount = selectable.filter((r, i) => this.isRowSelected(r, i)).length;
|
|
1437
|
+
return selectedCount > 0 && selectedCount < selectable.length;
|
|
1438
|
+
}
|
|
1439
|
+
selectAllLabel() {
|
|
1440
|
+
const labels = this.selectionA11yLabels || {};
|
|
1441
|
+
return this.isPageAllSelected()
|
|
1442
|
+
? (labels.unselectAll || 'Unselect all rows')
|
|
1443
|
+
: (labels.selectAll || 'Select all rows');
|
|
1444
|
+
}
|
|
1445
|
+
rowSelectionLabel(index) {
|
|
1446
|
+
const labels = this.selectionA11yLabels || {};
|
|
1447
|
+
const selected = this.isRowSelected(this.paged[index], index);
|
|
1448
|
+
return selected
|
|
1449
|
+
? (labels.unselectRow || `Unselect row ${index + 1}`)
|
|
1450
|
+
: (labels.selectRow || `Select row ${index + 1}`);
|
|
1451
|
+
}
|
|
1452
|
+
onRowSelect(ev, pagedIndex) {
|
|
1453
|
+
if (!this.isSelectionEnabled() || this.isCheckboxOnly())
|
|
1454
|
+
return;
|
|
1455
|
+
const target = ev.target;
|
|
1456
|
+
if (target.closest('input, button, a, select, textarea,label'))
|
|
1457
|
+
return;
|
|
1458
|
+
this.toggleSelection(pagedIndex, ev);
|
|
1459
|
+
}
|
|
1460
|
+
onHeaderScroll() {
|
|
1461
|
+
const body = this.bodyScroller?.nativeElement;
|
|
1462
|
+
const head = this.headerScroller?.nativeElement;
|
|
1463
|
+
if (body && head && body.scrollLeft !== head.scrollLeft) {
|
|
1464
|
+
body.scrollLeft = head.scrollLeft;
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
syncScrollbarWidth() {
|
|
1468
|
+
const el = this.bodyScroller?.nativeElement;
|
|
1469
|
+
if (!el)
|
|
1470
|
+
return;
|
|
1471
|
+
const width = el.offsetWidth - el.clientWidth;
|
|
1472
|
+
if (width !== this.scrollbarWidth) {
|
|
1473
|
+
this.scrollbarWidth = width;
|
|
1474
|
+
this.cdr.markForCheck();
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: Datagrid, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1478
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.9", type: Datagrid, isStandalone: true, selector: "ngb-datagrid", inputs: { columns: "columns", data: "data", enableSorting: "enableSorting", enableFiltering: "enableFiltering", enableGlobalFilter: "enableGlobalFilter", enablePagination: "enablePagination", enableEdit: "enableEdit", enableDelete: "enableDelete", pageSizeOptions: "pageSizeOptions", enableAdd: "enableAdd", addButtonAriaLabel: "addButtonAriaLabel", addButtonText: "addButtonText", stickyRows: "stickyRows", stickyHeader: "stickyHeader", stickyFooter: "stickyFooter", scrollable: "scrollable", stickyRowHeight: "stickyRowHeight", stickyHeaderHeight: "stickyHeaderHeight", stickyFooterHeight: "stickyFooterHeight", tableOptions: "tableOptions", selectionMode: "selectionMode", selectionBehavior: "selectionBehavior", selectionKeyMode: "selectionKeyMode", selectAllEnabled: "selectAllEnabled", selectionA11yLabels: "selectionA11yLabels", selectionDisabledFn: "selectionDisabledFn", highlightedIndex: "highlightedIndex", highlightRowKey: "highlightRowKey", highlightColKey: "highlightColKey", globalFilterAriaLabel: "globalFilterAriaLabel", expandRowAriaLabel: "expandRowAriaLabel", collapseRowAriaLabel: "collapseRowAriaLabel", exportPdfAriaLabel: "exportPdfAriaLabel", exportExcelAriaLabel: "exportExcelAriaLabel", newRowDefaults: "newRowDefaults", strictEmail: "strictEmail", editOnRowClick: "editOnRowClick", singleExpand: "singleExpand", exportOptions: "exportOptions", theme: "theme", responsive: "responsive", trackBy: "trackBy", editService: "editService", dataProviderAll: "dataProviderAll", dataProviderSelection: "dataProviderSelection", pageSize: "pageSize" }, outputs: { rowAdd: "rowAdd", rowEdit: "rowEdit", rowSave: "rowSave", rowCancel: "rowCancel", rowDelete: "rowDelete", sortChange: "sortChange", filtersChange: "filtersChange", pageChange: "pageChange", selectionChange: "selectionChange" }, providers: [
|
|
925
1479
|
{ provide: PdfExportAdapter, useClass: JsPdfAdapter },
|
|
926
1480
|
{ provide: ExcelExportAdapter, useClass: XlsxAdapter }
|
|
927
|
-
], queries: [{ propertyName: "exportButtonDir", first: true, predicate: ExportButtonDirective, descendants: true }, { propertyName: "rowDetailTpl", first: true, predicate: NgbRowDetailTemplate, descendants: true }, { propertyName: "cellTplQ", predicate: NgbCellTemplate }, { propertyName: "editTplQ", predicate: NgbEditorTemplate }, { propertyName: "filterTplQ", predicate: NgbFilterTemplate }, { propertyName: "globalTplQ", predicate: NgbGlobalFilterTemplate }], usesOnChanges: true, ngImport: i0, template: "<!-- eslint-disable @angular-eslint/template/interactive-supports-focus -->\n<!-- eslint-disable @angular-eslint/template/click-events-have-key-events -->\n<div class=\"ngb-grid\" [attr.data-theme]=\"theme\" [class.ngb-responsive]=\"isResponsiveEnabled()\">\n <!-- Export toolbar -->\n <div class=\"d-flex justify-content-end mb-2\" *ngIf=\"exportOptions?.enabled\">\n <ng-container *ngIf=\"exportButtonTpl; else defaultExportBtns\"\n [ngTemplateOutlet]=\"exportButtonTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: triggerExport }\">\n </ng-container>\n\n <ng-template #defaultExportBtns>\n <button type=\"button\"\n class=\"btn btn-sm btn-outline-secondary me-2\"\n *ngIf=\"exportOptions.type === 'pdf' || exportOptions.type === 'both'\"\n [disabled]=\"exporting\"\n (click)=\"export('pdf')\"\n [attr.aria-label]=\"exportAriaLabel('pdf')\">\n Export to PDF\n </button>\n <button type=\"button\"\n class=\"btn btn-sm btn-outline-secondary\"\n *ngIf=\"exportOptions.type === 'excel' || exportOptions.type === 'both'\"\n [disabled]=\"exporting\"\n (click)=\"export('excel')\"\n [attr.aria-label]=\"exportAriaLabel('excel')\">\n Export to Excel\n </button>\n </ng-template>\n </div>\n <div class=\"d-flex justify-content-end mb-2\" *ngIf=\"enableAdd\">\n <button\n type=\"button\"\n class=\"btn btn-sm btn-primary\"\n (click)=\"startAdd()\"\n [disabled]=\"addingNew\"\n [attr.aria-label]=\"addButtonAriaLabel || addButtonText\"\n >\n {{ addButtonText }}\n </button>\n </div>\n <!-- Global filter -->\n <div class=\"mb-2\" *ngIf=\"enableFiltering && enableGlobalFilter\">\n <ng-container\n *ngIf=\"globalTpl; else defaultGlobalFilter\"\n [ngTemplateOutlet]=\"globalTpl?.template\"\n [ngTemplateOutletContext]=\"{ $implicit: globalFilterCtrl }\"\n >\n </ng-container>\n\n <ng-template #defaultGlobalFilter>\n <input\n type=\"search\"\n class=\"form-control form-control-sm\"\n placeholder=\"Search all columns...\"\n [formControl]=\"globalFilterCtrl\"\n [attr.aria-label]=\"globalFilterAriaLabel\"\n />\n </ng-template>\n </div>\n\n <table class=\"table table-bordered\"\n role=\"grid\"\n [attr.aria-readonly]=\"(enableEdit || enableAdd) ? 'false' : 'true'\">\n <thead class=\"thead-light\">\n <tr>\n <th *ngIf=\"rowDetailTpl\" style=\"width:1%\" scope=\"col\" aria-hidden=\"true\"></th>\n <th\n *ngFor=\"let col of columns\"\n [attr.data-title]=\"col.header\"\n [class.sortable]=\"enableSorting && col.sortable\"\n scope=\"col\"\n [attr.aria-sort]=\"enableSorting && col.sortable ? ariaSortFor(col.field) : null\"\n >\n <ng-container *ngIf=\"enableSorting && col.sortable; else plainHeader\">\n <button\n type=\"button\"\n class=\"btn btn-link p-0 text-start w-100\"\n (click)=\"toggleSort(col.field)\"\n [attr.aria-label]=\"sortButtonAriaLabel(col)\"\n >\n <span>{{ col.header }}</span>\n <span\n class=\"sort-indicator\"\n *ngIf=\"enableSorting && sort.active === col.field\"\n aria-hidden=\"true\"\n >\n {{\n sort.direction === 'asc'\n ? '\u25B2'\n : sort.direction === 'desc'\n ? '\u25BC'\n : ''\n }}\n </span>\n </button>\n </ng-container>\n <ng-template #plainHeader>\n <span>{{ col.header }}</span>\n </ng-template>\n </th>\n <th\n *ngIf=\"enableEdit || enableDelete\"\n class=\"text-center\"\n scope=\"col\"\n style=\"width: 1%\"\n >\n Actions\n </th>\n </tr>\n\n <!-- Per-column filters -->\n <tr *ngIf=\"anyFilterable\" [formGroup]=\"filterForm\">\n <th *ngFor=\"let col of columns\" [attr.data-title]=\"col.header\">\n <ng-container *ngIf=\"col.filterable\">\n <ng-container *ngIf=\"filterTpls[col.field] as ft; else defaultFilter\">\n <ng-container\n [ngTemplateOutlet]=\"ft.template\"\n [ngTemplateOutletContext]=\"{\n $implicit: filterForm.get(col.field),\n control: filterForm.get(col.field),\n col: col\n }\"\n >\n </ng-container>\n </ng-container>\n <ng-template #defaultFilter>\n <input\n type=\"text\"\n class=\"form-control form-control-sm\"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"columnFilterAriaLabel(col)\"\n />\n </ng-template>\n </ng-container>\n </th>\n <th *ngIf=\"enableEdit || enableDelete\"></th>\n </tr>\n </thead>\n\n <tbody>\n <!-- ADD NEW ROW -->\n <tr *ngIf=\"addingNew\" [formGroup]=\"addForm\">\n <!-- blank caret cell to keep alignment when detail column is present -->\n <td *ngIf=\"rowDetailTpl\"></td>\n\n <td *ngFor=\"let col of columns\" [attr.data-title]=\"col.header\">\n <ng-container [ngSwitch]=\"col.type\">\n <!-- boolean -->\n <div\n *ngSwitchCase=\"'boolean'\"\n class=\"form-check m-0\"\n [class.is-invalid]=\"(addForm.get(col.field)?.touched || saveAttemptedNew) && addForm.get(col.field)?.invalid\">\n <input\n type=\"checkbox\"\n class=\"form-check-input\"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"inputAriaLabel(col)\"\n [attr.aria-invalid]=\"(addForm.get(col.field)?.touched || saveAttemptedNew) && addForm.get(col.field)?.invalid ? 'true' : null\"\n [attr.aria-describedby]=\"(addForm.get(col.field)?.touched || saveAttemptedNew) && addForm.get(col.field)?.invalid ? 'add-error-' + col.field : null\"\n />\n </div>\n\n <!-- number/email/date/text -->\n <input\n *ngSwitchDefault\n class=\"form-control form-control-sm\"\n [class.is-invalid]=\"(addForm.get(col.field)?.touched || saveAttemptedNew) && addForm.get(col.field)?.invalid\"\n [attr.type]=\"col.type === 'number' ? 'number' :\n col.type === 'email' ? 'email' :\n col.type === 'date' ? 'date' : 'text'\"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"inputAriaLabel(col)\"\n [attr.aria-invalid]=\"(addForm.get(col.field)?.touched || saveAttemptedNew) && addForm.get(col.field)?.invalid ? 'true' : null\"\n [attr.aria-describedby]=\"(addForm.get(col.field)?.touched || saveAttemptedNew) && addForm.get(col.field)?.invalid ? 'add-error-' + col.field : null\"\n />\n </ng-container>\n\n <div class=\"invalid-feedback d-block\"\n *ngIf=\"(addForm.get(col.field)?.touched || saveAttemptedNew) && addForm.get(col.field)?.errors as e\"\n [attr.id]=\"'add-error-' + col.field\"\n role=\"alert\">\n <ng-container *ngIf=\"e['required']\">Required</ng-container>\n <ng-container *ngIf=\"e['email']\">Invalid email</ng-container>\n <ng-container *ngIf=\"e['number']\">Invalid number</ng-container>\n <ng-container *ngIf=\"e['date']\">Invalid date</ng-container>\n </div>\n </td>\n\n <td *ngIf=\"enableEdit || enableDelete\" class=\"text-nowrap text-center\">\n <button type=\"button\" class=\"btn btn-sm btn-success me-1\" (click)=\"saveAdd()\" [disabled]=\"addForm.invalid\">Save</button>\n <button type=\"button\" class=\"btn btn-sm btn-secondary\" (click)=\"cancelAdd()\">Cancel</button>\n </td>\n </tr>\n\n <!-- DATA ROWS + DETAIL ROWS -->\n <ng-container *ngFor=\"let row of paged; let i = index; trackBy: trackRow\">\n\n <!-- DATA ROW (click-to-edit supported) -->\n <tr (click)=\"onRowClick($event, i)\" [formGroup]=\"editForm\">\n\n <!-- caret/expander cell (left-most) -->\n <td *ngIf=\"rowDetailTpl\" class=\"text-center align-middle\">\n <button\n type=\"button\"\n class=\"expand btn btn-link p-0\"\n (click)=\"$event.stopPropagation(); toggleExpand(i)\"\n [attr.aria-expanded]=\"isExpanded(i)\"\n [attr.aria-controls]=\"'dg-row-detail-' + i\"\n [attr.aria-label]=\"isExpanded(i) ? collapseRowAriaLabel : expandRowAriaLabel\">\n {{ isExpanded(i) ? '-' : '+' }}\n </button>\n </td>\n\n <!-- DATA CELLS -->\n <td *ngFor=\"let col of columns\" [attr.data-title]=\"col.header\">\n <!-- EDIT MODE -->\n <ng-container *ngIf=\"editingIndex === i && (col.editable ?? true); else readCell\">\n <!-- editor template override -->\n <ng-container *ngIf=\"editTpls[col.field] as et; else defaultEditor\"\n [ngTemplateOutlet]=\"et.template\"\n [ngTemplateOutletContext]=\"{\n $implicit: editForm.get(col.field),\n control: editForm.get(col.field),\n row: row, col: col, form: editForm, index: i, isNew: false\n }\">\n </ng-container>\n\n <!-- default editors -->\n <ng-template #defaultEditor>\n <ng-container [ngSwitch]=\"col.type\">\n <div *ngSwitchCase=\"'boolean'\" class=\"form-check m-0\">\n <input type=\"checkbox\"\n class=\"form-check-input\"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"inputAriaLabel(col)\"\n [attr.aria-invalid]=\"(editForm?.touched || saveAttemptedEdit) && editForm?.get(col.field)?.invalid ? 'true' : null\"\n [attr.aria-describedby]=\"(editForm?.touched || saveAttemptedEdit) && editForm?.get(col.field)?.invalid ? 'edit-error-' + col.field : null\" />\n </div>\n <select *ngSwitchCase=\"'select'\"\n class=\"form-select form-select-sm\"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"inputAriaLabel(col)\">\n <option *ngFor=\"let o of col.options ?? []\" [ngValue]=\"o.value\">{{ o.label }}</option>\n </select>\n <input *ngSwitchDefault\n class=\"form-control form-control-sm\"\n [attr.type]=\"col.type === 'number' ? 'number' :\n col.type === 'email' ? 'email' :\n col.type === 'date' ? 'date' : 'text'\"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"inputAriaLabel(col)\"\n [attr.aria-invalid]=\"(editForm?.touched || saveAttemptedEdit) && editForm?.get(col.field)?.invalid ? 'true' : null\"\n [attr.aria-describedby]=\"(editForm?.touched || saveAttemptedEdit) && editForm?.get(col.field)?.invalid ? 'edit-error-' + col.field : null\" />\n </ng-container>\n\n <div class=\"invalid-feedback d-block\"\n *ngIf=\"(editForm?.touched || saveAttemptedEdit) && editForm?.get(col.field)?.errors as e\"\n [attr.id]=\"'edit-error-' + col.field\"\n role=\"alert\">\n <span *ngIf=\"e['required']\">Required</span>\n <span *ngIf=\"e['email']\">Invalid email</span>\n <span *ngIf=\"e['number']\">Invalid number</span>\n <span *ngIf=\"e['date']\">Invalid date</span>\n </div>\n </ng-template>\n </ng-container>\n\n <!-- READ MODE (with optional cell template) -->\n <ng-template #readCell>\n <ng-container *ngIf=\"cellTpls[col.field] as ct; else defaultCell\"\n [ngTemplateOutlet]=\"ct.template\"\n [ngTemplateOutletContext]=\"{ $implicit: row[col.field], row: row, col: col, index: i }\">\n </ng-container>\n <ng-template #defaultCell>\n <ng-container [ngSwitch]=\"col.type\">\n <span *ngSwitchCase=\"'boolean'\">{{ row[col.field] ? 'Yes' : 'No' }}</span>\n <span *ngSwitchDefault>{{ row[col.field] }}</span>\n </ng-container>\n </ng-template>\n </ng-template>\n </td>\n\n <!-- ACTIONS -->\n <td *ngIf=\"enableEdit || enableDelete\" class=\"text-nowrap text-center\">\n <ng-container *ngIf=\"editingIndex !== i; else editBtns\">\n <button type=\"button\" *ngIf=\"enableEdit\" class=\"btn btn-sm btn-outline-primary me-1 no-edit-trigger\" (click)=\"startEdit(i)\">Edit</button>\n <button type=\"button\" *ngIf=\"enableDelete\" class=\"btn btn-sm btn-outline-danger no-edit-trigger\" (click)=\"deleteRow(i)\">Delete</button>\n </ng-container>\n <ng-template #editBtns>\n <button type=\"button\" class=\"btn btn-sm btn-success me-1\" (click)=\"saveEdit(i)\" [disabled]=\"editForm.invalid\">Save</button>\n <button type=\"button\" class=\"btn btn-sm btn-secondary\" (click)=\"cancelEdit(i)\">Cancel</button>\n </ng-template>\n </td>\n </tr>\n\n <!-- DETAIL ROW (spans all columns) -->\n <tr *ngIf=\"rowDetailTpl && isExpanded(i)\" [attr.id]=\"'dg-row-detail-' + i\">\n <td [attr.colspan]=\"detailColspan\" role=\"region\">\n <ng-container [ngTemplateOutlet]=\"rowDetailTpl.template\"\n [ngTemplateOutletContext]=\"{ $implicit: row, index: i }\">\n </ng-container>\n </td>\n </tr>\n\n </ng-container>\n </tbody>\n\n </table>\n\n <!-- Footer (left = count, center = pagination, right = page size) -->\n <div *ngIf=\"enablePagination\" class=\"d-flex align-items-center justify-content-between mt-2\">\n <!-- left: count -->\n <div class=\"small text-muted\" aria-live=\"polite\">\n {{ startIndex }} - {{ endIndex }} of {{ sorted.length }}\n\n </div>\n\n <!-- center: pager -->\n <div class=\"flex-grow-1 d-flex justify-content-center\">\n <ngb-pagination\n [page]=\"page\"\n [pageSize]=\"pageSize\"\n [collectionSize]=\"sorted.length\"\n [maxSize]=\"5\"\n (pageChange)=\"onPage($event)\">\n </ngb-pagination>\n </div>\n\n <!-- right: rows per page -->\n <div class=\"d-flex align-items-center gap-2\">\n <label class=\"form-label form-label-sm mb-0\" for=\"pageSize\">Rows:</label>\n <select\n id=\"pageSize\"\n class=\"form-select form-select-sm\"\n [(ngModel)]=\"pageSize\"\n (ngModelChange)=\"onPageSize($event)\"\n aria-label=\"Rows per page\">\n <option *ngFor=\"let s of pageSizeOptions\" [value]=\"s\">{{ s }}</option>\n </select>\n </div>\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block}.table{margin-bottom:.5rem}th.sortable{cursor:pointer;-webkit-user-select:none;user-select:none}.sort-indicator{margin-left:.35rem;font-size:.75rem}.expand{cursor:pointer;font-size:24px;line-height:18px;display:block}.ngb-grid[data-theme=material]{--ngb-primary: #3f51b5}.ngb-grid[data-theme=material] .btn{border-color:var(--ngb-primary)}.ngb-grid[data-theme=material] table.table th,.ngb-grid[data-theme=material] table.table td{border-bottom:1px solid #e5e7eb}.ngb-grid[data-theme=tailwind]{--ngb-primary: rgb(29 78 216)}.ngb-grid[data-theme=tailwind] .btn{border-color:var(--ngb-primary);border-radius:.75rem}.ngb-grid[data-theme=tailwind] table.table th,.ngb-grid[data-theme=tailwind] table.table td{border-bottom:1px solid #e5e7eb;padding:.5rem}.ngb-responsive .table{width:100%}@media(max-width:768px){.ngb-responsive thead{display:none}.ngb-responsive tbody tr{display:grid;grid-template-columns:1fr;gap:.5rem;border:1px solid #e5e7eb;border-radius:.75rem;padding:.75rem;margin-bottom:.75rem}.ngb-responsive tbody td{display:grid;grid-template-columns:8rem 1fr}.ngb-responsive tbody td:before{content:attr(data-title);font-weight:600;opacity:.75;padding-right:.5rem}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i1.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: NgbPaginationComponent, selector: "ngb-pagination", inputs: ["page", "pageSize", "collectionSize", "maxSize"], outputs: ["pageChange"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1481
|
+
], queries: [{ propertyName: "exportButtonDir", first: true, predicate: ExportButtonDirective, descendants: true }, { propertyName: "rowDetailTpl", first: true, predicate: NgbRowDetailTemplate, descendants: true }, { propertyName: "cellTplQ", predicate: NgbCellTemplate }, { propertyName: "editTplQ", predicate: NgbEditorTemplate }, { propertyName: "filterTplQ", predicate: NgbFilterTemplate }, { propertyName: "globalTplQ", predicate: NgbGlobalFilterTemplate }], viewQueries: [{ propertyName: "bodyScroller", first: true, predicate: ["bodyScroller"], descendants: true }, { propertyName: "headerScroller", first: true, predicate: ["headerScroller"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<!-- eslint-disable @angular-eslint/template/interactive-supports-focus -->\n<!-- eslint-disable @angular-eslint/template/click-events-have-key-events -->\n<div class=\"ngb-grid\" [attr.data-theme]=\"theme\" [class.ngb-responsive]=\"isResponsiveEnabled()\">\n <!-- Export toolbar -->\n <div class=\"d-flex justify-content-end mb-2\" *ngIf=\"exportOptions?.enabled\">\n <ng-container *ngIf=\"exportButtonTpl; else defaultExportBtns\"\n [ngTemplateOutlet]=\"exportButtonTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: triggerExport }\">\n </ng-container>\n\n <ng-template #defaultExportBtns>\n <button type=\"button\"\n class=\"btn btn-sm btn-outline-secondary me-2\"\n *ngIf=\"exportOptions.type === 'pdf' || exportOptions.type === 'both'\"\n [disabled]=\"exporting\"\n (click)=\"export('pdf')\"\n [attr.aria-label]=\"exportAriaLabel('pdf')\">\n Export to PDF\n </button>\n <button type=\"button\"\n class=\"btn btn-sm btn-outline-secondary\"\n *ngIf=\"exportOptions.type === 'excel' || exportOptions.type === 'both'\"\n [disabled]=\"exporting\"\n (click)=\"export('excel')\"\n [attr.aria-label]=\"exportAriaLabel('excel')\">\n Export to Excel\n </button>\n </ng-template>\n </div>\n <div class=\"d-flex justify-content-end mb-2\" *ngIf=\"enableAdd\">\n <button\n type=\"button\"\n class=\"btn btn-sm btn-primary\"\n (click)=\"startAdd()\"\n [disabled]=\"addingNew\"\n [attr.aria-label]=\"addButtonAriaLabel || addButtonText\"\n >\n {{ addButtonText }}\n </button>\n </div>\n <!-- Global filter -->\n <div class=\"mb-2\" *ngIf=\"enableFiltering && enableGlobalFilter\">\n <ng-container\n *ngIf=\"globalTpl; else defaultGlobalFilter\"\n [ngTemplateOutlet]=\"globalTpl?.template\"\n [ngTemplateOutletContext]=\"{ $implicit: globalFilterCtrl }\"\n >\n </ng-container>\n\n <ng-template #defaultGlobalFilter>\n <input\n type=\"search\"\n class=\"form-control form-control-sm\"\n placeholder=\"Search all columns...\"\n [formControl]=\"globalFilterCtrl\"\n [attr.aria-label]=\"globalFilterAriaLabel\"\n />\n </ng-template>\n </div>\n\n <div class=\"table-wrapper\"\n [class.scrollable]=\"shouldEnableScroll\"\n [ngClass]=\"responsiveWrapperClasses\">\n <div class=\"table-header\" [style.paddingRight.px]=\"scrollbarWidth\" #headerScroller (scroll)=\"onHeaderScroll()\">\n <table [ngClass]=\"tableClassList\">\n <caption *ngIf=\"tableOptions?.caption\"\n [class.caption-top]=\"(tableOptions?.captionSide ?? 'top') === 'top'\">\n {{ tableOptions?.caption }}\n </caption>\n <colgroup [ngbSyncColgroup]=\"colgroupSyncId\" syncRole=\"header\">\n <col *ngIf=\"isSelectionEnabled()\" style=\"width:1%\">\n <col *ngIf=\"rowDetailTpl\" style=\"width:1%\">\n <col *ngIf=\"stickyRowsEnabled\" style=\"width:1%\">\n <col *ngFor=\"let col of columns\">\n <col *ngIf=\"enableEdit || enableDelete\" style=\"width:1%\">\n </colgroup>\n <thead class=\"thead-light\">\n <tr>\n <th *ngIf=\"isSelectionEnabled()\" class=\"text-center\" scope=\"col\" style=\"width:1%\">\n <ng-container *ngIf=\"selectionMode === 'multiple' && selectAllEnabled\">\n <input type=\"checkbox\"\n [checked]=\"isPageAllSelected()\"\n [indeterminate]=\"isPageIndeterminate()\"\n (change)=\"toggleSelectAllCurrentPage()\"\n [attr.aria-label]=\"selectAllLabel()\">\n </ng-container>\n </th>\n <th *ngIf=\"rowDetailTpl\" style=\"width:1%\" scope=\"col\" aria-hidden=\"true\"></th>\n <th *ngIf=\"stickyRowsEnabled\" style=\"width:1%\" scope=\"col\" class=\"text-center\" data-title=\"Sticky\"></th>\n <th\n *ngFor=\"let col of columns\"\n [attr.data-title]=\"col.header\"\n [class.sortable]=\"enableSorting && col.sortable\"\n scope=\"col\"\n [attr.aria-sort]=\"enableSorting && col.sortable ? ariaSortFor(col.field) : null\"\n >\n <ng-container *ngIf=\"enableSorting && col.sortable; else plainHeader\">\n <button\n type=\"button\"\n class=\"btn btn-link p-0 text-start w-100\"\n (click)=\"toggleSort(col.field)\"\n [attr.aria-label]=\"sortButtonAriaLabel(col)\"\n >\n <span>{{ col.header }}</span>\n <span\n class=\"sort-indicator\"\n *ngIf=\"enableSorting && sort.active === col.field\"\n aria-hidden=\"true\"\n >\n {{\n sort.direction === 'asc'\n ? '\u25B2'\n : sort.direction === 'desc'\n ? '\u25BC'\n : ''\n }}\n </span>\n </button>\n </ng-container>\n <ng-template #plainHeader>\n <span>{{ col.header }}</span>\n </ng-template>\n </th>\n <th\n *ngIf=\"enableEdit || enableDelete\"\n class=\"text-center\"\n scope=\"col\"\n style=\"width: 1%\"\n >\n Actions\n </th>\n </tr>\n\n <!-- Per-column filters -->\n <tr *ngIf=\"anyFilterable\" [formGroup]=\"filterForm\">\n <th *ngIf=\"isSelectionEnabled()\"></th>\n <th *ngIf=\"stickyRowsEnabled\"></th>\n <th *ngFor=\"let col of columns\" [attr.data-title]=\"col.header\">\n <ng-container *ngIf=\"col.filterable\">\n <ng-container *ngIf=\"filterTpls[col.field] as ft; else defaultFilter\">\n <ng-container\n [ngTemplateOutlet]=\"ft.template\"\n [ngTemplateOutletContext]=\"{\n $implicit: filterForm.get(col.field),\n control: filterForm.get(col.field),\n col: col\n }\"\n >\n </ng-container>\n </ng-container>\n <ng-template #defaultFilter>\n <input\n type=\"text\"\n class=\"form-control form-control-sm\"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"columnFilterAriaLabel(col)\"\n />\n </ng-template>\n </ng-container>\n </th>\n <th *ngIf=\"enableEdit || enableDelete\"></th>\n </tr>\n </thead>\n </table>\n </div>\n\n <div class=\"table-body\" #bodyScroller>\n <table [ngClass]=\"tableClassList\"\n role=\"grid\"\n [attr.aria-readonly]=\"(enableEdit || enableAdd) ? 'false' : 'true'\">\n <colgroup [ngbSyncColgroup]=\"colgroupSyncId\" syncRole=\"body\">\n <col *ngIf=\"isSelectionEnabled()\" style=\"width:1%\">\n <col *ngIf=\"rowDetailTpl\" style=\"width:1%\">\n <col *ngIf=\"stickyRowsEnabled\" style=\"width:1%\">\n <col *ngFor=\"let col of columns\">\n <col *ngIf=\"enableEdit || enableDelete\" style=\"width:1%\">\n </colgroup>\n <tbody>\n <!-- ADD NEW ROW -->\n <tr *ngIf=\"addingNew\" [formGroup]=\"addForm\">\n <!-- blank caret cell to keep alignment when detail column is present -->\n <td *ngIf=\"isSelectionEnabled()\"></td>\n <td *ngIf=\"rowDetailTpl\"></td>\n <td *ngIf=\"stickyRowsEnabled\" class=\"text-center\"></td>\n\n <td *ngFor=\"let col of columns\" [attr.data-title]=\"col.header\">\n <ng-container [ngSwitch]=\"col.type\">\n <!-- boolean -->\n <div\n *ngSwitchCase=\"'boolean'\"\n class=\"form-check m-0\"\n [class.is-invalid]=\"(addForm.get(col.field)?.touched || saveAttemptedNew) && addForm.get(col.field)?.invalid\">\n <input\n type=\"checkbox\"\n class=\"form-check-input\"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"inputAriaLabel(col)\"\n [attr.aria-invalid]=\"(addForm.get(col.field)?.touched || saveAttemptedNew) && addForm.get(col.field)?.invalid ? 'true' : null\"\n [attr.aria-describedby]=\"(addForm.get(col.field)?.touched || saveAttemptedNew) && addForm.get(col.field)?.invalid ? 'add-error-' + col.field : null\"\n />\n </div>\n\n <!-- number/email/date/text -->\n <input\n *ngSwitchDefault\n class=\"form-control form-control-sm\"\n [class.is-invalid]=\"(addForm.get(col.field)?.touched || saveAttemptedNew) && addForm.get(col.field)?.invalid\"\n [attr.type]=\"col.type === 'number' ? 'number' :\n col.type === 'email' ? 'email' :\n col.type === 'date' ? 'date' : 'text'\"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"inputAriaLabel(col)\"\n [attr.aria-invalid]=\"(addForm.get(col.field)?.touched || saveAttemptedNew) && addForm.get(col.field)?.invalid ? 'true' : null\"\n [attr.aria-describedby]=\"(addForm.get(col.field)?.touched || saveAttemptedNew) && addForm.get(col.field)?.invalid ? 'add-error-' + col.field : null\"\n />\n </ng-container>\n\n <div class=\"invalid-feedback d-block\"\n *ngIf=\"(addForm.get(col.field)?.touched || saveAttemptedNew) && addForm.get(col.field)?.errors as e\"\n [attr.id]=\"'add-error-' + col.field\"\n role=\"alert\">\n <ng-container *ngIf=\"e['required']\">Required</ng-container>\n <ng-container *ngIf=\"e['email']\">Invalid email</ng-container>\n <ng-container *ngIf=\"e['number']\">Invalid number</ng-container>\n <ng-container *ngIf=\"e['date']\">Invalid date</ng-container>\n </div>\n </td>\n\n <td *ngIf=\"enableEdit || enableDelete\" class=\"text-nowrap text-center\">\n <button type=\"button\" class=\"btn btn-sm btn-success me-1\" (click)=\"saveAdd()\" [disabled]=\"addForm.invalid\">Save</button>\n <button type=\"button\" class=\"btn btn-sm btn-secondary\" (click)=\"cancelAdd()\">Cancel</button>\n </td>\n </tr>\n\n <!-- DATA ROWS + DETAIL ROWS -->\n <ng-container *ngFor=\"let row of paged; let i = index; trackBy: trackRow\">\n\n <!-- DATA ROW (click-to-edit supported) -->\n <tr (click)=\"onRowSelect($event, i); onRowClick($event, i)\" [formGroup]=\"editForm\"\n [class.sticky-row]=\"isRowSticky(row, i)\"\n [class.row-selected]=\"isRowSelected(row, i)\"\n [class.row-highlight]=\"isRowHighlighted(row, i)\"\n [attr.aria-selected]=\"isRowSelected(row, i) ? 'true' : null\"\n [style.top.px]=\"stickyTop(row, i)\"\n [style.z-index]=\"isRowSticky(row, i) ? 3 : null\">\n\n <td *ngIf=\"isSelectionEnabled()\" class=\"text-center align-middle\">\n <input type=\"checkbox\"\n [checked]=\"isRowSelected(row, i)\"\n [disabled]=\"selectionMode === 'none' || selectionBehavior === 'row' || isSelectionDisabled(row, i)\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleSelection(i, $event)\"\n [attr.aria-label]=\"rowSelectionLabel(i)\">\n </td>\n\n <!-- caret/expander cell (left-most) -->\n <td *ngIf=\"rowDetailTpl\" class=\"text-center align-middle\">\n <button\n type=\"button\"\n class=\"expand btn btn-link p-0\"\n (click)=\"$event.stopPropagation(); toggleExpand(i)\"\n [attr.aria-expanded]=\"isExpanded(i)\"\n [attr.aria-controls]=\"'dg-row-detail-' + i\"\n [attr.aria-label]=\"isExpanded(i) ? collapseRowAriaLabel : expandRowAriaLabel\">\n {{ isExpanded(i) ? '-' : '+' }}\n </button>\n </td>\n\n <td *ngIf=\"stickyRowsEnabled\" class=\"text-center align-middle\" data-title=\"Sticky\">\n <button\n type=\"button\"\n class=\"btn btn-link p-0 no-edit-trigger sticky-toggle\"\n (click)=\"$event.stopPropagation(); toggleStickyRow(i)\"\n [attr.aria-pressed]=\"isRowSticky(row, i)\"\n aria-label=\"Toggle sticky row\">\n <ng-container *ngIf=\"stickyIcon(row, i) as icon\">\n <span class=\"bi\" [ngClass]=\"'bi-' + icon\" aria-hidden=\"true\"></span>\n </ng-container>\n </button>\n </td>\n\n <!-- DATA CELLS -->\n <td *ngFor=\"let col of columns; let ci = index\"\n [attr.data-title]=\"col.header\"\n [class.cell-highlight]=\"isCellHighlighted(row, i, col, ci)\">\n <!-- EDIT MODE -->\n <ng-container *ngIf=\"editingIndex === i && (col.editable ?? true); else readCell\">\n <!-- editor template override -->\n <ng-container *ngIf=\"editTpls[col.field] as et; else defaultEditor\"\n [ngTemplateOutlet]=\"et.template\"\n [ngTemplateOutletContext]=\"{\n $implicit: editForm.get(col.field),\n control: editForm.get(col.field),\n row: row, col: col, form: editForm, index: i, isNew: false\n }\">\n </ng-container>\n\n <!-- default editors -->\n <ng-template #defaultEditor>\n <ng-container [ngSwitch]=\"col.type\">\n <div *ngSwitchCase=\"'boolean'\" class=\"form-check m-0\">\n <input type=\"checkbox\"\n class=\"form-check-input\"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"inputAriaLabel(col)\"\n [attr.aria-invalid]=\"(editForm?.touched || saveAttemptedEdit) && editForm?.get(col.field)?.invalid ? 'true' : null\"\n [attr.aria-describedby]=\"(editForm?.touched || saveAttemptedEdit) && editForm?.get(col.field)?.invalid ? 'edit-error-' + col.field : null\" />\n </div>\n <select *ngSwitchCase=\"'select'\"\n class=\"form-select form-select-sm\"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"inputAriaLabel(col)\">\n <option *ngFor=\"let o of col.options ?? []\" [ngValue]=\"o.value\">{{ o.label }}</option>\n </select>\n <input *ngSwitchDefault\n class=\"form-control form-control-sm\"\n [attr.type]=\"col.type === 'number' ? 'number' :\n col.type === 'email' ? 'email' :\n col.type === 'date' ? 'date' : 'text'\"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"inputAriaLabel(col)\"\n [attr.aria-invalid]=\"(editForm?.touched || saveAttemptedEdit) && editForm?.get(col.field)?.invalid ? 'true' : null\"\n [attr.aria-describedby]=\"(editForm?.touched || saveAttemptedEdit) && editForm?.get(col.field)?.invalid ? 'edit-error-' + col.field : null\" />\n </ng-container>\n\n <div class=\"invalid-feedback d-block\"\n *ngIf=\"(editForm?.touched || saveAttemptedEdit) && editForm?.get(col.field)?.errors as e\"\n [attr.id]=\"'edit-error-' + col.field\"\n role=\"alert\">\n <span *ngIf=\"e['required']\">Required</span>\n <span *ngIf=\"e['email']\">Invalid email</span>\n <span *ngIf=\"e['number']\">Invalid number</span>\n <span *ngIf=\"e['date']\">Invalid date</span>\n </div>\n </ng-template>\n </ng-container>\n\n <!-- READ MODE (with optional cell template) -->\n <ng-template #readCell>\n <ng-container *ngIf=\"cellTpls[col.field] as ct; else defaultCell\"\n [ngTemplateOutlet]=\"ct.template\"\n [ngTemplateOutletContext]=\"{ $implicit: row[col.field], row: row, col: col, index: i }\">\n </ng-container>\n <ng-template #defaultCell>\n <ng-container [ngSwitch]=\"col.type\">\n <span *ngSwitchCase=\"'boolean'\">{{ row[col.field] ? 'Yes' : 'No' }}</span>\n <span *ngSwitchDefault>{{ row[col.field] }}</span>\n </ng-container>\n </ng-template>\n </ng-template>\n </td>\n\n <!-- ACTIONS -->\n <td *ngIf=\"enableEdit || enableDelete\" class=\"text-nowrap text-center\">\n <ng-container *ngIf=\"editingIndex !== i; else editBtns\">\n <button type=\"button\" *ngIf=\"enableEdit\" class=\"btn btn-sm btn-outline-primary me-1 no-edit-trigger\" (click)=\"startEdit(i)\">Edit</button>\n <button type=\"button\" *ngIf=\"enableDelete\" class=\"btn btn-sm btn-outline-danger no-edit-trigger\" (click)=\"deleteRow(i)\">Delete</button>\n </ng-container>\n <ng-template #editBtns>\n <button type=\"button\" class=\"btn btn-sm btn-success me-1\" (click)=\"saveEdit(i)\" [disabled]=\"editForm.invalid\">Save</button>\n <button type=\"button\" class=\"btn btn-sm btn-secondary\" (click)=\"cancelEdit(i)\">Cancel</button>\n </ng-template>\n </td>\n </tr>\n\n <!-- DETAIL ROW (spans all columns) -->\n <tr *ngIf=\"rowDetailTpl && isExpanded(i)\" [attr.id]=\"'dg-row-detail-' + i\">\n <td [attr.colspan]=\"detailColspan\" role=\"region\">\n <ng-container [ngTemplateOutlet]=\"rowDetailTpl.template\"\n [ngTemplateOutletContext]=\"{ $implicit: row, index: i }\">\n </ng-container>\n </td>\n </tr>\n\n </ng-container>\n </tbody>\n\n </table>\n </div>\n </div>\n</div>\n\n<!-- Footer (left = count, center = pagination, right = page size) -->\n<div *ngIf=\"enablePagination\"\n class=\"d-flex align-items-center justify-content-between mt-2 grid-footer\"\n [class.sticky-footer]=\"isFooterSticky\">\n <!-- left: count -->\n <div class=\"small text-muted\" aria-live=\"polite\">\n {{ startIndex }} - {{ endIndex }} of {{ sorted.length }}\n\n </div>\n\n <!-- center: pager -->\n <div class=\"flex-grow-1 d-flex justify-content-center\">\n <ngb-pagination\n [page]=\"page\"\n [pageSize]=\"pageSize\"\n [collectionSize]=\"sorted.length\"\n [maxSize]=\"5\"\n (pageChange)=\"onPage($event)\">\n </ngb-pagination>\n </div>\n\n <!-- right: rows per page -->\n <div class=\"d-flex align-items-center gap-2\">\n <label class=\"form-label form-label-sm mb-0\" for=\"pageSize\">Rows:</label>\n <select\n id=\"pageSize\"\n class=\"form-select form-select-sm\"\n [(ngModel)]=\"pageSize\"\n (ngModelChange)=\"onPageSize($event)\"\n aria-label=\"Rows per page\">\n <option *ngFor=\"let s of pageSizeOptions\" [value]=\"s\">{{ s }}</option>\n </select>\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block}.table{margin-bottom:.5rem}th.sortable{cursor:pointer;-webkit-user-select:none;user-select:none}.sort-indicator{margin-left:.35rem;font-size:.75rem}.expand{cursor:pointer;font-size:24px;line-height:18px;display:block}.sticky-toggle{display:inline-flex;align-items:center;justify-content:center;gap:.15rem}.table-wrapper{position:relative}.table-wrapper{display:flex;flex-direction:column}.table-wrapper .table{table-layout:fixed;width:100%;margin-bottom:0}.table-header{overflow-x:auto;overflow-y:hidden}.table-body{max-height:60vh;overflow:auto;scrollbar-gutter:stable}.table-header th,.table-body td{min-width:40px;max-width:320px;word-break:break-word}.table-header th{white-space:nowrap}.table-body td{white-space:normal}.table-header col,.table-body col{min-width:40px;max-width:320px}.table-wrapper.sticky-header thead th{position:sticky;top:0;z-index:5;background:#ccc}.table-wrapper.sticky-footer .grid-footer{position:sticky;bottom:0;z-index:5;background:#fff;border-top:1px solid #e2e2e2;border-left:1px solid #e2e2e2;border-right:1px solid #e2e2e2;padding:5px 20px}.sticky-row{position:sticky;background:#ccc;z-index:4}.sticky-row td{background:#ccc}.row-selected{background-color:#e7f1ff}.row-highlight{background-color:var(--bs-warning-bg-subtle, #fff3cd)}.row-highlight td{background-color:inherit}.cell-highlight{background-color:var(--bs-info-bg-subtle, #cff4fc)}.ngb-grid[data-theme=material]{--ngb-primary: #3f51b5}.ngb-grid[data-theme=material] .btn{border-color:var(--ngb-primary)}.ngb-grid[data-theme=material] table.table th,.ngb-grid[data-theme=material] table.table td{border-bottom:1px solid #e5e7eb}.ngb-grid[data-theme=tailwind]{--ngb-primary: rgb(29 78 216)}.ngb-grid[data-theme=tailwind] .btn{border-color:var(--ngb-primary);border-radius:.75rem}.ngb-grid[data-theme=tailwind] table.table th,.ngb-grid[data-theme=tailwind] table.table td{border-bottom:1px solid #e5e7eb;padding:.5rem}.ngb-responsive .table{width:100%}@media(max-width:768px){.ngb-responsive thead{display:none}.ngb-responsive tbody tr{display:grid;grid-template-columns:1fr;gap:.5rem;border:1px solid #e5e7eb;border-radius:.75rem;padding:.75rem;margin-bottom:.75rem}.ngb-responsive tbody td{display:grid;grid-template-columns:8rem 1fr}.ngb-responsive tbody td:before{content:attr(data-title);font-weight:600;opacity:.75;padding-right:.5rem}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i1.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: NgbPaginationComponent, selector: "ngb-pagination", inputs: ["page", "pageSize", "collectionSize", "maxSize"], outputs: ["pageChange"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: NgbSyncColgroupDirective, selector: "[ngbSyncColgroup]", inputs: ["ngbSyncColgroup", "syncRole"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
928
1482
|
}
|
|
929
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.
|
|
1483
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: Datagrid, decorators: [{
|
|
930
1484
|
type: Component,
|
|
931
|
-
args: [{ selector: 'ngb-datagrid', imports: [CommonModule, FormsModule, NgbPaginationComponent, ReactiveFormsModule], providers: [
|
|
1485
|
+
args: [{ selector: 'ngb-datagrid', imports: [CommonModule, FormsModule, NgbPaginationComponent, ReactiveFormsModule, NgbSyncColgroupDirective, NgbGridHighlightDirective], providers: [
|
|
932
1486
|
{ provide: PdfExportAdapter, useClass: JsPdfAdapter },
|
|
933
1487
|
{ provide: ExcelExportAdapter, useClass: XlsxAdapter }
|
|
934
|
-
], standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- eslint-disable @angular-eslint/template/interactive-supports-focus -->\n<!-- eslint-disable @angular-eslint/template/click-events-have-key-events -->\n<div class=\"ngb-grid\" [attr.data-theme]=\"theme\" [class.ngb-responsive]=\"isResponsiveEnabled()\">\n <!-- Export toolbar -->\n <div class=\"d-flex justify-content-end mb-2\" *ngIf=\"exportOptions?.enabled\">\n <ng-container *ngIf=\"exportButtonTpl; else defaultExportBtns\"\n [ngTemplateOutlet]=\"exportButtonTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: triggerExport }\">\n </ng-container>\n\n <ng-template #defaultExportBtns>\n <button type=\"button\"\n class=\"btn btn-sm btn-outline-secondary me-2\"\n *ngIf=\"exportOptions.type === 'pdf' || exportOptions.type === 'both'\"\n [disabled]=\"exporting\"\n (click)=\"export('pdf')\"\n [attr.aria-label]=\"exportAriaLabel('pdf')\">\n Export to PDF\n </button>\n <button type=\"button\"\n class=\"btn btn-sm btn-outline-secondary\"\n *ngIf=\"exportOptions.type === 'excel' || exportOptions.type === 'both'\"\n [disabled]=\"exporting\"\n (click)=\"export('excel')\"\n [attr.aria-label]=\"exportAriaLabel('excel')\">\n Export to Excel\n </button>\n </ng-template>\n </div>\n <div class=\"d-flex justify-content-end mb-2\" *ngIf=\"enableAdd\">\n <button\n type=\"button\"\n class=\"btn btn-sm btn-primary\"\n (click)=\"startAdd()\"\n [disabled]=\"addingNew\"\n [attr.aria-label]=\"addButtonAriaLabel || addButtonText\"\n >\n {{ addButtonText }}\n </button>\n </div>\n <!-- Global filter -->\n <div class=\"mb-2\" *ngIf=\"enableFiltering && enableGlobalFilter\">\n <ng-container\n *ngIf=\"globalTpl; else defaultGlobalFilter\"\n [ngTemplateOutlet]=\"globalTpl?.template\"\n [ngTemplateOutletContext]=\"{ $implicit: globalFilterCtrl }\"\n >\n </ng-container>\n\n <ng-template #defaultGlobalFilter>\n <input\n type=\"search\"\n class=\"form-control form-control-sm\"\n placeholder=\"Search all columns...\"\n [formControl]=\"globalFilterCtrl\"\n [attr.aria-label]=\"globalFilterAriaLabel\"\n />\n </ng-template>\n </div>\n\n <table class=\"table table-bordered\"\n role=\"grid\"\n [attr.aria-readonly]=\"(enableEdit || enableAdd) ? 'false' : 'true'\">\n <thead class=\"thead-light\">\n <tr>\n <th *ngIf=\"rowDetailTpl\" style=\"width:1%\" scope=\"col\" aria-hidden=\"true\"></th>\n <th\n *ngFor=\"let col of columns\"\n [attr.data-title]=\"col.header\"\n [class.sortable]=\"enableSorting && col.sortable\"\n scope=\"col\"\n [attr.aria-sort]=\"enableSorting && col.sortable ? ariaSortFor(col.field) : null\"\n >\n <ng-container *ngIf=\"enableSorting && col.sortable; else plainHeader\">\n <button\n type=\"button\"\n class=\"btn btn-link p-0 text-start w-100\"\n (click)=\"toggleSort(col.field)\"\n [attr.aria-label]=\"sortButtonAriaLabel(col)\"\n >\n <span>{{ col.header }}</span>\n <span\n class=\"sort-indicator\"\n *ngIf=\"enableSorting && sort.active === col.field\"\n aria-hidden=\"true\"\n >\n {{\n sort.direction === 'asc'\n ? '\u25B2'\n : sort.direction === 'desc'\n ? '\u25BC'\n : ''\n }}\n </span>\n </button>\n </ng-container>\n <ng-template #plainHeader>\n <span>{{ col.header }}</span>\n </ng-template>\n </th>\n <th\n *ngIf=\"enableEdit || enableDelete\"\n class=\"text-center\"\n scope=\"col\"\n style=\"width: 1%\"\n >\n Actions\n </th>\n </tr>\n\n <!-- Per-column filters -->\n <tr *ngIf=\"anyFilterable\" [formGroup]=\"filterForm\">\n <th *ngFor=\"let col of columns\" [attr.data-title]=\"col.header\">\n <ng-container *ngIf=\"col.filterable\">\n <ng-container *ngIf=\"filterTpls[col.field] as ft; else defaultFilter\">\n <ng-container\n [ngTemplateOutlet]=\"ft.template\"\n [ngTemplateOutletContext]=\"{\n $implicit: filterForm.get(col.field),\n control: filterForm.get(col.field),\n col: col\n }\"\n >\n </ng-container>\n </ng-container>\n <ng-template #defaultFilter>\n <input\n type=\"text\"\n class=\"form-control form-control-sm\"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"columnFilterAriaLabel(col)\"\n />\n </ng-template>\n </ng-container>\n </th>\n <th *ngIf=\"enableEdit || enableDelete\"></th>\n </tr>\n </thead>\n\n <tbody>\n <!-- ADD NEW ROW -->\n <tr *ngIf=\"addingNew\" [formGroup]=\"addForm\">\n <!-- blank caret cell to keep alignment when detail column is present -->\n <td *ngIf=\"rowDetailTpl\"></td>\n\n <td *ngFor=\"let col of columns\" [attr.data-title]=\"col.header\">\n <ng-container [ngSwitch]=\"col.type\">\n <!-- boolean -->\n <div\n *ngSwitchCase=\"'boolean'\"\n class=\"form-check m-0\"\n [class.is-invalid]=\"(addForm.get(col.field)?.touched || saveAttemptedNew) && addForm.get(col.field)?.invalid\">\n <input\n type=\"checkbox\"\n class=\"form-check-input\"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"inputAriaLabel(col)\"\n [attr.aria-invalid]=\"(addForm.get(col.field)?.touched || saveAttemptedNew) && addForm.get(col.field)?.invalid ? 'true' : null\"\n [attr.aria-describedby]=\"(addForm.get(col.field)?.touched || saveAttemptedNew) && addForm.get(col.field)?.invalid ? 'add-error-' + col.field : null\"\n />\n </div>\n\n <!-- number/email/date/text -->\n <input\n *ngSwitchDefault\n class=\"form-control form-control-sm\"\n [class.is-invalid]=\"(addForm.get(col.field)?.touched || saveAttemptedNew) && addForm.get(col.field)?.invalid\"\n [attr.type]=\"col.type === 'number' ? 'number' :\n col.type === 'email' ? 'email' :\n col.type === 'date' ? 'date' : 'text'\"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"inputAriaLabel(col)\"\n [attr.aria-invalid]=\"(addForm.get(col.field)?.touched || saveAttemptedNew) && addForm.get(col.field)?.invalid ? 'true' : null\"\n [attr.aria-describedby]=\"(addForm.get(col.field)?.touched || saveAttemptedNew) && addForm.get(col.field)?.invalid ? 'add-error-' + col.field : null\"\n />\n </ng-container>\n\n <div class=\"invalid-feedback d-block\"\n *ngIf=\"(addForm.get(col.field)?.touched || saveAttemptedNew) && addForm.get(col.field)?.errors as e\"\n [attr.id]=\"'add-error-' + col.field\"\n role=\"alert\">\n <ng-container *ngIf=\"e['required']\">Required</ng-container>\n <ng-container *ngIf=\"e['email']\">Invalid email</ng-container>\n <ng-container *ngIf=\"e['number']\">Invalid number</ng-container>\n <ng-container *ngIf=\"e['date']\">Invalid date</ng-container>\n </div>\n </td>\n\n <td *ngIf=\"enableEdit || enableDelete\" class=\"text-nowrap text-center\">\n <button type=\"button\" class=\"btn btn-sm btn-success me-1\" (click)=\"saveAdd()\" [disabled]=\"addForm.invalid\">Save</button>\n <button type=\"button\" class=\"btn btn-sm btn-secondary\" (click)=\"cancelAdd()\">Cancel</button>\n </td>\n </tr>\n\n <!-- DATA ROWS + DETAIL ROWS -->\n <ng-container *ngFor=\"let row of paged; let i = index; trackBy: trackRow\">\n\n <!-- DATA ROW (click-to-edit supported) -->\n <tr (click)=\"onRowClick($event, i)\" [formGroup]=\"editForm\">\n\n <!-- caret/expander cell (left-most) -->\n <td *ngIf=\"rowDetailTpl\" class=\"text-center align-middle\">\n <button\n type=\"button\"\n class=\"expand btn btn-link p-0\"\n (click)=\"$event.stopPropagation(); toggleExpand(i)\"\n [attr.aria-expanded]=\"isExpanded(i)\"\n [attr.aria-controls]=\"'dg-row-detail-' + i\"\n [attr.aria-label]=\"isExpanded(i) ? collapseRowAriaLabel : expandRowAriaLabel\">\n {{ isExpanded(i) ? '-' : '+' }}\n </button>\n </td>\n\n <!-- DATA CELLS -->\n <td *ngFor=\"let col of columns\" [attr.data-title]=\"col.header\">\n <!-- EDIT MODE -->\n <ng-container *ngIf=\"editingIndex === i && (col.editable ?? true); else readCell\">\n <!-- editor template override -->\n <ng-container *ngIf=\"editTpls[col.field] as et; else defaultEditor\"\n [ngTemplateOutlet]=\"et.template\"\n [ngTemplateOutletContext]=\"{\n $implicit: editForm.get(col.field),\n control: editForm.get(col.field),\n row: row, col: col, form: editForm, index: i, isNew: false\n }\">\n </ng-container>\n\n <!-- default editors -->\n <ng-template #defaultEditor>\n <ng-container [ngSwitch]=\"col.type\">\n <div *ngSwitchCase=\"'boolean'\" class=\"form-check m-0\">\n <input type=\"checkbox\"\n class=\"form-check-input\"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"inputAriaLabel(col)\"\n [attr.aria-invalid]=\"(editForm?.touched || saveAttemptedEdit) && editForm?.get(col.field)?.invalid ? 'true' : null\"\n [attr.aria-describedby]=\"(editForm?.touched || saveAttemptedEdit) && editForm?.get(col.field)?.invalid ? 'edit-error-' + col.field : null\" />\n </div>\n <select *ngSwitchCase=\"'select'\"\n class=\"form-select form-select-sm\"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"inputAriaLabel(col)\">\n <option *ngFor=\"let o of col.options ?? []\" [ngValue]=\"o.value\">{{ o.label }}</option>\n </select>\n <input *ngSwitchDefault\n class=\"form-control form-control-sm\"\n [attr.type]=\"col.type === 'number' ? 'number' :\n col.type === 'email' ? 'email' :\n col.type === 'date' ? 'date' : 'text'\"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"inputAriaLabel(col)\"\n [attr.aria-invalid]=\"(editForm?.touched || saveAttemptedEdit) && editForm?.get(col.field)?.invalid ? 'true' : null\"\n [attr.aria-describedby]=\"(editForm?.touched || saveAttemptedEdit) && editForm?.get(col.field)?.invalid ? 'edit-error-' + col.field : null\" />\n </ng-container>\n\n <div class=\"invalid-feedback d-block\"\n *ngIf=\"(editForm?.touched || saveAttemptedEdit) && editForm?.get(col.field)?.errors as e\"\n [attr.id]=\"'edit-error-' + col.field\"\n role=\"alert\">\n <span *ngIf=\"e['required']\">Required</span>\n <span *ngIf=\"e['email']\">Invalid email</span>\n <span *ngIf=\"e['number']\">Invalid number</span>\n <span *ngIf=\"e['date']\">Invalid date</span>\n </div>\n </ng-template>\n </ng-container>\n\n <!-- READ MODE (with optional cell template) -->\n <ng-template #readCell>\n <ng-container *ngIf=\"cellTpls[col.field] as ct; else defaultCell\"\n [ngTemplateOutlet]=\"ct.template\"\n [ngTemplateOutletContext]=\"{ $implicit: row[col.field], row: row, col: col, index: i }\">\n </ng-container>\n <ng-template #defaultCell>\n <ng-container [ngSwitch]=\"col.type\">\n <span *ngSwitchCase=\"'boolean'\">{{ row[col.field] ? 'Yes' : 'No' }}</span>\n <span *ngSwitchDefault>{{ row[col.field] }}</span>\n </ng-container>\n </ng-template>\n </ng-template>\n </td>\n\n <!-- ACTIONS -->\n <td *ngIf=\"enableEdit || enableDelete\" class=\"text-nowrap text-center\">\n <ng-container *ngIf=\"editingIndex !== i; else editBtns\">\n <button type=\"button\" *ngIf=\"enableEdit\" class=\"btn btn-sm btn-outline-primary me-1 no-edit-trigger\" (click)=\"startEdit(i)\">Edit</button>\n <button type=\"button\" *ngIf=\"enableDelete\" class=\"btn btn-sm btn-outline-danger no-edit-trigger\" (click)=\"deleteRow(i)\">Delete</button>\n </ng-container>\n <ng-template #editBtns>\n <button type=\"button\" class=\"btn btn-sm btn-success me-1\" (click)=\"saveEdit(i)\" [disabled]=\"editForm.invalid\">Save</button>\n <button type=\"button\" class=\"btn btn-sm btn-secondary\" (click)=\"cancelEdit(i)\">Cancel</button>\n </ng-template>\n </td>\n </tr>\n\n <!-- DETAIL ROW (spans all columns) -->\n <tr *ngIf=\"rowDetailTpl && isExpanded(i)\" [attr.id]=\"'dg-row-detail-' + i\">\n <td [attr.colspan]=\"detailColspan\" role=\"region\">\n <ng-container [ngTemplateOutlet]=\"rowDetailTpl.template\"\n [ngTemplateOutletContext]=\"{ $implicit: row, index: i }\">\n </ng-container>\n </td>\n </tr>\n\n </ng-container>\n </tbody>\n\n </table>\n\n <!-- Footer (left = count, center = pagination, right = page size) -->\n <div *ngIf=\"enablePagination\" class=\"d-flex align-items-center justify-content-between mt-2\">\n <!-- left: count -->\n <div class=\"small text-muted\" aria-live=\"polite\">\n {{ startIndex }} - {{ endIndex }} of {{ sorted.length }}\n\n </div>\n\n <!-- center: pager -->\n <div class=\"flex-grow-1 d-flex justify-content-center\">\n <ngb-pagination\n [page]=\"page\"\n [pageSize]=\"pageSize\"\n [collectionSize]=\"sorted.length\"\n [maxSize]=\"5\"\n (pageChange)=\"onPage($event)\">\n </ngb-pagination>\n </div>\n\n <!-- right: rows per page -->\n <div class=\"d-flex align-items-center gap-2\">\n <label class=\"form-label form-label-sm mb-0\" for=\"pageSize\">Rows:</label>\n <select\n id=\"pageSize\"\n class=\"form-select form-select-sm\"\n [(ngModel)]=\"pageSize\"\n (ngModelChange)=\"onPageSize($event)\"\n aria-label=\"Rows per page\">\n <option *ngFor=\"let s of pageSizeOptions\" [value]=\"s\">{{ s }}</option>\n </select>\n </div>\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block}.table{margin-bottom:.5rem}th.sortable{cursor:pointer;-webkit-user-select:none;user-select:none}.sort-indicator{margin-left:.35rem;font-size:.75rem}.expand{cursor:pointer;font-size:24px;line-height:18px;display:block}.ngb-grid[data-theme=material]{--ngb-primary: #3f51b5}.ngb-grid[data-theme=material] .btn{border-color:var(--ngb-primary)}.ngb-grid[data-theme=material] table.table th,.ngb-grid[data-theme=material] table.table td{border-bottom:1px solid #e5e7eb}.ngb-grid[data-theme=tailwind]{--ngb-primary: rgb(29 78 216)}.ngb-grid[data-theme=tailwind] .btn{border-color:var(--ngb-primary);border-radius:.75rem}.ngb-grid[data-theme=tailwind] table.table th,.ngb-grid[data-theme=tailwind] table.table td{border-bottom:1px solid #e5e7eb;padding:.5rem}.ngb-responsive .table{width:100%}@media(max-width:768px){.ngb-responsive thead{display:none}.ngb-responsive tbody tr{display:grid;grid-template-columns:1fr;gap:.5rem;border:1px solid #e5e7eb;border-radius:.75rem;padding:.75rem;margin-bottom:.75rem}.ngb-responsive tbody td{display:grid;grid-template-columns:8rem 1fr}.ngb-responsive tbody td:before{content:attr(data-title);font-weight:600;opacity:.75;padding-right:.5rem}}\n"] }]
|
|
1488
|
+
], standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- eslint-disable @angular-eslint/template/interactive-supports-focus -->\n<!-- eslint-disable @angular-eslint/template/click-events-have-key-events -->\n<div class=\"ngb-grid\" [attr.data-theme]=\"theme\" [class.ngb-responsive]=\"isResponsiveEnabled()\">\n <!-- Export toolbar -->\n <div class=\"d-flex justify-content-end mb-2\" *ngIf=\"exportOptions?.enabled\">\n <ng-container *ngIf=\"exportButtonTpl; else defaultExportBtns\"\n [ngTemplateOutlet]=\"exportButtonTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: triggerExport }\">\n </ng-container>\n\n <ng-template #defaultExportBtns>\n <button type=\"button\"\n class=\"btn btn-sm btn-outline-secondary me-2\"\n *ngIf=\"exportOptions.type === 'pdf' || exportOptions.type === 'both'\"\n [disabled]=\"exporting\"\n (click)=\"export('pdf')\"\n [attr.aria-label]=\"exportAriaLabel('pdf')\">\n Export to PDF\n </button>\n <button type=\"button\"\n class=\"btn btn-sm btn-outline-secondary\"\n *ngIf=\"exportOptions.type === 'excel' || exportOptions.type === 'both'\"\n [disabled]=\"exporting\"\n (click)=\"export('excel')\"\n [attr.aria-label]=\"exportAriaLabel('excel')\">\n Export to Excel\n </button>\n </ng-template>\n </div>\n <div class=\"d-flex justify-content-end mb-2\" *ngIf=\"enableAdd\">\n <button\n type=\"button\"\n class=\"btn btn-sm btn-primary\"\n (click)=\"startAdd()\"\n [disabled]=\"addingNew\"\n [attr.aria-label]=\"addButtonAriaLabel || addButtonText\"\n >\n {{ addButtonText }}\n </button>\n </div>\n <!-- Global filter -->\n <div class=\"mb-2\" *ngIf=\"enableFiltering && enableGlobalFilter\">\n <ng-container\n *ngIf=\"globalTpl; else defaultGlobalFilter\"\n [ngTemplateOutlet]=\"globalTpl?.template\"\n [ngTemplateOutletContext]=\"{ $implicit: globalFilterCtrl }\"\n >\n </ng-container>\n\n <ng-template #defaultGlobalFilter>\n <input\n type=\"search\"\n class=\"form-control form-control-sm\"\n placeholder=\"Search all columns...\"\n [formControl]=\"globalFilterCtrl\"\n [attr.aria-label]=\"globalFilterAriaLabel\"\n />\n </ng-template>\n </div>\n\n <div class=\"table-wrapper\"\n [class.scrollable]=\"shouldEnableScroll\"\n [ngClass]=\"responsiveWrapperClasses\">\n <div class=\"table-header\" [style.paddingRight.px]=\"scrollbarWidth\" #headerScroller (scroll)=\"onHeaderScroll()\">\n <table [ngClass]=\"tableClassList\">\n <caption *ngIf=\"tableOptions?.caption\"\n [class.caption-top]=\"(tableOptions?.captionSide ?? 'top') === 'top'\">\n {{ tableOptions?.caption }}\n </caption>\n <colgroup [ngbSyncColgroup]=\"colgroupSyncId\" syncRole=\"header\">\n <col *ngIf=\"isSelectionEnabled()\" style=\"width:1%\">\n <col *ngIf=\"rowDetailTpl\" style=\"width:1%\">\n <col *ngIf=\"stickyRowsEnabled\" style=\"width:1%\">\n <col *ngFor=\"let col of columns\">\n <col *ngIf=\"enableEdit || enableDelete\" style=\"width:1%\">\n </colgroup>\n <thead class=\"thead-light\">\n <tr>\n <th *ngIf=\"isSelectionEnabled()\" class=\"text-center\" scope=\"col\" style=\"width:1%\">\n <ng-container *ngIf=\"selectionMode === 'multiple' && selectAllEnabled\">\n <input type=\"checkbox\"\n [checked]=\"isPageAllSelected()\"\n [indeterminate]=\"isPageIndeterminate()\"\n (change)=\"toggleSelectAllCurrentPage()\"\n [attr.aria-label]=\"selectAllLabel()\">\n </ng-container>\n </th>\n <th *ngIf=\"rowDetailTpl\" style=\"width:1%\" scope=\"col\" aria-hidden=\"true\"></th>\n <th *ngIf=\"stickyRowsEnabled\" style=\"width:1%\" scope=\"col\" class=\"text-center\" data-title=\"Sticky\"></th>\n <th\n *ngFor=\"let col of columns\"\n [attr.data-title]=\"col.header\"\n [class.sortable]=\"enableSorting && col.sortable\"\n scope=\"col\"\n [attr.aria-sort]=\"enableSorting && col.sortable ? ariaSortFor(col.field) : null\"\n >\n <ng-container *ngIf=\"enableSorting && col.sortable; else plainHeader\">\n <button\n type=\"button\"\n class=\"btn btn-link p-0 text-start w-100\"\n (click)=\"toggleSort(col.field)\"\n [attr.aria-label]=\"sortButtonAriaLabel(col)\"\n >\n <span>{{ col.header }}</span>\n <span\n class=\"sort-indicator\"\n *ngIf=\"enableSorting && sort.active === col.field\"\n aria-hidden=\"true\"\n >\n {{\n sort.direction === 'asc'\n ? '\u25B2'\n : sort.direction === 'desc'\n ? '\u25BC'\n : ''\n }}\n </span>\n </button>\n </ng-container>\n <ng-template #plainHeader>\n <span>{{ col.header }}</span>\n </ng-template>\n </th>\n <th\n *ngIf=\"enableEdit || enableDelete\"\n class=\"text-center\"\n scope=\"col\"\n style=\"width: 1%\"\n >\n Actions\n </th>\n </tr>\n\n <!-- Per-column filters -->\n <tr *ngIf=\"anyFilterable\" [formGroup]=\"filterForm\">\n <th *ngIf=\"isSelectionEnabled()\"></th>\n <th *ngIf=\"stickyRowsEnabled\"></th>\n <th *ngFor=\"let col of columns\" [attr.data-title]=\"col.header\">\n <ng-container *ngIf=\"col.filterable\">\n <ng-container *ngIf=\"filterTpls[col.field] as ft; else defaultFilter\">\n <ng-container\n [ngTemplateOutlet]=\"ft.template\"\n [ngTemplateOutletContext]=\"{\n $implicit: filterForm.get(col.field),\n control: filterForm.get(col.field),\n col: col\n }\"\n >\n </ng-container>\n </ng-container>\n <ng-template #defaultFilter>\n <input\n type=\"text\"\n class=\"form-control form-control-sm\"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"columnFilterAriaLabel(col)\"\n />\n </ng-template>\n </ng-container>\n </th>\n <th *ngIf=\"enableEdit || enableDelete\"></th>\n </tr>\n </thead>\n </table>\n </div>\n\n <div class=\"table-body\" #bodyScroller>\n <table [ngClass]=\"tableClassList\"\n role=\"grid\"\n [attr.aria-readonly]=\"(enableEdit || enableAdd) ? 'false' : 'true'\">\n <colgroup [ngbSyncColgroup]=\"colgroupSyncId\" syncRole=\"body\">\n <col *ngIf=\"isSelectionEnabled()\" style=\"width:1%\">\n <col *ngIf=\"rowDetailTpl\" style=\"width:1%\">\n <col *ngIf=\"stickyRowsEnabled\" style=\"width:1%\">\n <col *ngFor=\"let col of columns\">\n <col *ngIf=\"enableEdit || enableDelete\" style=\"width:1%\">\n </colgroup>\n <tbody>\n <!-- ADD NEW ROW -->\n <tr *ngIf=\"addingNew\" [formGroup]=\"addForm\">\n <!-- blank caret cell to keep alignment when detail column is present -->\n <td *ngIf=\"isSelectionEnabled()\"></td>\n <td *ngIf=\"rowDetailTpl\"></td>\n <td *ngIf=\"stickyRowsEnabled\" class=\"text-center\"></td>\n\n <td *ngFor=\"let col of columns\" [attr.data-title]=\"col.header\">\n <ng-container [ngSwitch]=\"col.type\">\n <!-- boolean -->\n <div\n *ngSwitchCase=\"'boolean'\"\n class=\"form-check m-0\"\n [class.is-invalid]=\"(addForm.get(col.field)?.touched || saveAttemptedNew) && addForm.get(col.field)?.invalid\">\n <input\n type=\"checkbox\"\n class=\"form-check-input\"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"inputAriaLabel(col)\"\n [attr.aria-invalid]=\"(addForm.get(col.field)?.touched || saveAttemptedNew) && addForm.get(col.field)?.invalid ? 'true' : null\"\n [attr.aria-describedby]=\"(addForm.get(col.field)?.touched || saveAttemptedNew) && addForm.get(col.field)?.invalid ? 'add-error-' + col.field : null\"\n />\n </div>\n\n <!-- number/email/date/text -->\n <input\n *ngSwitchDefault\n class=\"form-control form-control-sm\"\n [class.is-invalid]=\"(addForm.get(col.field)?.touched || saveAttemptedNew) && addForm.get(col.field)?.invalid\"\n [attr.type]=\"col.type === 'number' ? 'number' :\n col.type === 'email' ? 'email' :\n col.type === 'date' ? 'date' : 'text'\"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"inputAriaLabel(col)\"\n [attr.aria-invalid]=\"(addForm.get(col.field)?.touched || saveAttemptedNew) && addForm.get(col.field)?.invalid ? 'true' : null\"\n [attr.aria-describedby]=\"(addForm.get(col.field)?.touched || saveAttemptedNew) && addForm.get(col.field)?.invalid ? 'add-error-' + col.field : null\"\n />\n </ng-container>\n\n <div class=\"invalid-feedback d-block\"\n *ngIf=\"(addForm.get(col.field)?.touched || saveAttemptedNew) && addForm.get(col.field)?.errors as e\"\n [attr.id]=\"'add-error-' + col.field\"\n role=\"alert\">\n <ng-container *ngIf=\"e['required']\">Required</ng-container>\n <ng-container *ngIf=\"e['email']\">Invalid email</ng-container>\n <ng-container *ngIf=\"e['number']\">Invalid number</ng-container>\n <ng-container *ngIf=\"e['date']\">Invalid date</ng-container>\n </div>\n </td>\n\n <td *ngIf=\"enableEdit || enableDelete\" class=\"text-nowrap text-center\">\n <button type=\"button\" class=\"btn btn-sm btn-success me-1\" (click)=\"saveAdd()\" [disabled]=\"addForm.invalid\">Save</button>\n <button type=\"button\" class=\"btn btn-sm btn-secondary\" (click)=\"cancelAdd()\">Cancel</button>\n </td>\n </tr>\n\n <!-- DATA ROWS + DETAIL ROWS -->\n <ng-container *ngFor=\"let row of paged; let i = index; trackBy: trackRow\">\n\n <!-- DATA ROW (click-to-edit supported) -->\n <tr (click)=\"onRowSelect($event, i); onRowClick($event, i)\" [formGroup]=\"editForm\"\n [class.sticky-row]=\"isRowSticky(row, i)\"\n [class.row-selected]=\"isRowSelected(row, i)\"\n [class.row-highlight]=\"isRowHighlighted(row, i)\"\n [attr.aria-selected]=\"isRowSelected(row, i) ? 'true' : null\"\n [style.top.px]=\"stickyTop(row, i)\"\n [style.z-index]=\"isRowSticky(row, i) ? 3 : null\">\n\n <td *ngIf=\"isSelectionEnabled()\" class=\"text-center align-middle\">\n <input type=\"checkbox\"\n [checked]=\"isRowSelected(row, i)\"\n [disabled]=\"selectionMode === 'none' || selectionBehavior === 'row' || isSelectionDisabled(row, i)\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleSelection(i, $event)\"\n [attr.aria-label]=\"rowSelectionLabel(i)\">\n </td>\n\n <!-- caret/expander cell (left-most) -->\n <td *ngIf=\"rowDetailTpl\" class=\"text-center align-middle\">\n <button\n type=\"button\"\n class=\"expand btn btn-link p-0\"\n (click)=\"$event.stopPropagation(); toggleExpand(i)\"\n [attr.aria-expanded]=\"isExpanded(i)\"\n [attr.aria-controls]=\"'dg-row-detail-' + i\"\n [attr.aria-label]=\"isExpanded(i) ? collapseRowAriaLabel : expandRowAriaLabel\">\n {{ isExpanded(i) ? '-' : '+' }}\n </button>\n </td>\n\n <td *ngIf=\"stickyRowsEnabled\" class=\"text-center align-middle\" data-title=\"Sticky\">\n <button\n type=\"button\"\n class=\"btn btn-link p-0 no-edit-trigger sticky-toggle\"\n (click)=\"$event.stopPropagation(); toggleStickyRow(i)\"\n [attr.aria-pressed]=\"isRowSticky(row, i)\"\n aria-label=\"Toggle sticky row\">\n <ng-container *ngIf=\"stickyIcon(row, i) as icon\">\n <span class=\"bi\" [ngClass]=\"'bi-' + icon\" aria-hidden=\"true\"></span>\n </ng-container>\n </button>\n </td>\n\n <!-- DATA CELLS -->\n <td *ngFor=\"let col of columns; let ci = index\"\n [attr.data-title]=\"col.header\"\n [class.cell-highlight]=\"isCellHighlighted(row, i, col, ci)\">\n <!-- EDIT MODE -->\n <ng-container *ngIf=\"editingIndex === i && (col.editable ?? true); else readCell\">\n <!-- editor template override -->\n <ng-container *ngIf=\"editTpls[col.field] as et; else defaultEditor\"\n [ngTemplateOutlet]=\"et.template\"\n [ngTemplateOutletContext]=\"{\n $implicit: editForm.get(col.field),\n control: editForm.get(col.field),\n row: row, col: col, form: editForm, index: i, isNew: false\n }\">\n </ng-container>\n\n <!-- default editors -->\n <ng-template #defaultEditor>\n <ng-container [ngSwitch]=\"col.type\">\n <div *ngSwitchCase=\"'boolean'\" class=\"form-check m-0\">\n <input type=\"checkbox\"\n class=\"form-check-input\"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"inputAriaLabel(col)\"\n [attr.aria-invalid]=\"(editForm?.touched || saveAttemptedEdit) && editForm?.get(col.field)?.invalid ? 'true' : null\"\n [attr.aria-describedby]=\"(editForm?.touched || saveAttemptedEdit) && editForm?.get(col.field)?.invalid ? 'edit-error-' + col.field : null\" />\n </div>\n <select *ngSwitchCase=\"'select'\"\n class=\"form-select form-select-sm\"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"inputAriaLabel(col)\">\n <option *ngFor=\"let o of col.options ?? []\" [ngValue]=\"o.value\">{{ o.label }}</option>\n </select>\n <input *ngSwitchDefault\n class=\"form-control form-control-sm\"\n [attr.type]=\"col.type === 'number' ? 'number' :\n col.type === 'email' ? 'email' :\n col.type === 'date' ? 'date' : 'text'\"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"inputAriaLabel(col)\"\n [attr.aria-invalid]=\"(editForm?.touched || saveAttemptedEdit) && editForm?.get(col.field)?.invalid ? 'true' : null\"\n [attr.aria-describedby]=\"(editForm?.touched || saveAttemptedEdit) && editForm?.get(col.field)?.invalid ? 'edit-error-' + col.field : null\" />\n </ng-container>\n\n <div class=\"invalid-feedback d-block\"\n *ngIf=\"(editForm?.touched || saveAttemptedEdit) && editForm?.get(col.field)?.errors as e\"\n [attr.id]=\"'edit-error-' + col.field\"\n role=\"alert\">\n <span *ngIf=\"e['required']\">Required</span>\n <span *ngIf=\"e['email']\">Invalid email</span>\n <span *ngIf=\"e['number']\">Invalid number</span>\n <span *ngIf=\"e['date']\">Invalid date</span>\n </div>\n </ng-template>\n </ng-container>\n\n <!-- READ MODE (with optional cell template) -->\n <ng-template #readCell>\n <ng-container *ngIf=\"cellTpls[col.field] as ct; else defaultCell\"\n [ngTemplateOutlet]=\"ct.template\"\n [ngTemplateOutletContext]=\"{ $implicit: row[col.field], row: row, col: col, index: i }\">\n </ng-container>\n <ng-template #defaultCell>\n <ng-container [ngSwitch]=\"col.type\">\n <span *ngSwitchCase=\"'boolean'\">{{ row[col.field] ? 'Yes' : 'No' }}</span>\n <span *ngSwitchDefault>{{ row[col.field] }}</span>\n </ng-container>\n </ng-template>\n </ng-template>\n </td>\n\n <!-- ACTIONS -->\n <td *ngIf=\"enableEdit || enableDelete\" class=\"text-nowrap text-center\">\n <ng-container *ngIf=\"editingIndex !== i; else editBtns\">\n <button type=\"button\" *ngIf=\"enableEdit\" class=\"btn btn-sm btn-outline-primary me-1 no-edit-trigger\" (click)=\"startEdit(i)\">Edit</button>\n <button type=\"button\" *ngIf=\"enableDelete\" class=\"btn btn-sm btn-outline-danger no-edit-trigger\" (click)=\"deleteRow(i)\">Delete</button>\n </ng-container>\n <ng-template #editBtns>\n <button type=\"button\" class=\"btn btn-sm btn-success me-1\" (click)=\"saveEdit(i)\" [disabled]=\"editForm.invalid\">Save</button>\n <button type=\"button\" class=\"btn btn-sm btn-secondary\" (click)=\"cancelEdit(i)\">Cancel</button>\n </ng-template>\n </td>\n </tr>\n\n <!-- DETAIL ROW (spans all columns) -->\n <tr *ngIf=\"rowDetailTpl && isExpanded(i)\" [attr.id]=\"'dg-row-detail-' + i\">\n <td [attr.colspan]=\"detailColspan\" role=\"region\">\n <ng-container [ngTemplateOutlet]=\"rowDetailTpl.template\"\n [ngTemplateOutletContext]=\"{ $implicit: row, index: i }\">\n </ng-container>\n </td>\n </tr>\n\n </ng-container>\n </tbody>\n\n </table>\n </div>\n </div>\n</div>\n\n<!-- Footer (left = count, center = pagination, right = page size) -->\n<div *ngIf=\"enablePagination\"\n class=\"d-flex align-items-center justify-content-between mt-2 grid-footer\"\n [class.sticky-footer]=\"isFooterSticky\">\n <!-- left: count -->\n <div class=\"small text-muted\" aria-live=\"polite\">\n {{ startIndex }} - {{ endIndex }} of {{ sorted.length }}\n\n </div>\n\n <!-- center: pager -->\n <div class=\"flex-grow-1 d-flex justify-content-center\">\n <ngb-pagination\n [page]=\"page\"\n [pageSize]=\"pageSize\"\n [collectionSize]=\"sorted.length\"\n [maxSize]=\"5\"\n (pageChange)=\"onPage($event)\">\n </ngb-pagination>\n </div>\n\n <!-- right: rows per page -->\n <div class=\"d-flex align-items-center gap-2\">\n <label class=\"form-label form-label-sm mb-0\" for=\"pageSize\">Rows:</label>\n <select\n id=\"pageSize\"\n class=\"form-select form-select-sm\"\n [(ngModel)]=\"pageSize\"\n (ngModelChange)=\"onPageSize($event)\"\n aria-label=\"Rows per page\">\n <option *ngFor=\"let s of pageSizeOptions\" [value]=\"s\">{{ s }}</option>\n </select>\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block}.table{margin-bottom:.5rem}th.sortable{cursor:pointer;-webkit-user-select:none;user-select:none}.sort-indicator{margin-left:.35rem;font-size:.75rem}.expand{cursor:pointer;font-size:24px;line-height:18px;display:block}.sticky-toggle{display:inline-flex;align-items:center;justify-content:center;gap:.15rem}.table-wrapper{position:relative}.table-wrapper{display:flex;flex-direction:column}.table-wrapper .table{table-layout:fixed;width:100%;margin-bottom:0}.table-header{overflow-x:auto;overflow-y:hidden}.table-body{max-height:60vh;overflow:auto;scrollbar-gutter:stable}.table-header th,.table-body td{min-width:40px;max-width:320px;word-break:break-word}.table-header th{white-space:nowrap}.table-body td{white-space:normal}.table-header col,.table-body col{min-width:40px;max-width:320px}.table-wrapper.sticky-header thead th{position:sticky;top:0;z-index:5;background:#ccc}.table-wrapper.sticky-footer .grid-footer{position:sticky;bottom:0;z-index:5;background:#fff;border-top:1px solid #e2e2e2;border-left:1px solid #e2e2e2;border-right:1px solid #e2e2e2;padding:5px 20px}.sticky-row{position:sticky;background:#ccc;z-index:4}.sticky-row td{background:#ccc}.row-selected{background-color:#e7f1ff}.row-highlight{background-color:var(--bs-warning-bg-subtle, #fff3cd)}.row-highlight td{background-color:inherit}.cell-highlight{background-color:var(--bs-info-bg-subtle, #cff4fc)}.ngb-grid[data-theme=material]{--ngb-primary: #3f51b5}.ngb-grid[data-theme=material] .btn{border-color:var(--ngb-primary)}.ngb-grid[data-theme=material] table.table th,.ngb-grid[data-theme=material] table.table td{border-bottom:1px solid #e5e7eb}.ngb-grid[data-theme=tailwind]{--ngb-primary: rgb(29 78 216)}.ngb-grid[data-theme=tailwind] .btn{border-color:var(--ngb-primary);border-radius:.75rem}.ngb-grid[data-theme=tailwind] table.table th,.ngb-grid[data-theme=tailwind] table.table td{border-bottom:1px solid #e5e7eb;padding:.5rem}.ngb-responsive .table{width:100%}@media(max-width:768px){.ngb-responsive thead{display:none}.ngb-responsive tbody tr{display:grid;grid-template-columns:1fr;gap:.5rem;border:1px solid #e5e7eb;border-radius:.75rem;padding:.75rem;margin-bottom:.75rem}.ngb-responsive tbody td{display:grid;grid-template-columns:8rem 1fr}.ngb-responsive tbody td:before{content:attr(data-title);font-weight:600;opacity:.75;padding-right:.5rem}}\n"] }]
|
|
935
1489
|
}], propDecorators: { columns: [{
|
|
936
1490
|
type: Input
|
|
937
1491
|
}], data: [{
|
|
@@ -956,6 +1510,40 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
|
|
|
956
1510
|
type: Input
|
|
957
1511
|
}], addButtonText: [{
|
|
958
1512
|
type: Input
|
|
1513
|
+
}], stickyRows: [{
|
|
1514
|
+
type: Input
|
|
1515
|
+
}], stickyHeader: [{
|
|
1516
|
+
type: Input
|
|
1517
|
+
}], stickyFooter: [{
|
|
1518
|
+
type: Input
|
|
1519
|
+
}], scrollable: [{
|
|
1520
|
+
type: Input
|
|
1521
|
+
}], stickyRowHeight: [{
|
|
1522
|
+
type: Input
|
|
1523
|
+
}], stickyHeaderHeight: [{
|
|
1524
|
+
type: Input
|
|
1525
|
+
}], stickyFooterHeight: [{
|
|
1526
|
+
type: Input
|
|
1527
|
+
}], tableOptions: [{
|
|
1528
|
+
type: Input
|
|
1529
|
+
}], selectionMode: [{
|
|
1530
|
+
type: Input
|
|
1531
|
+
}], selectionBehavior: [{
|
|
1532
|
+
type: Input
|
|
1533
|
+
}], selectionKeyMode: [{
|
|
1534
|
+
type: Input
|
|
1535
|
+
}], selectAllEnabled: [{
|
|
1536
|
+
type: Input
|
|
1537
|
+
}], selectionA11yLabels: [{
|
|
1538
|
+
type: Input
|
|
1539
|
+
}], selectionDisabledFn: [{
|
|
1540
|
+
type: Input
|
|
1541
|
+
}], highlightedIndex: [{
|
|
1542
|
+
type: Input
|
|
1543
|
+
}], highlightRowKey: [{
|
|
1544
|
+
type: Input
|
|
1545
|
+
}], highlightColKey: [{
|
|
1546
|
+
type: Input
|
|
959
1547
|
}], globalFilterAriaLabel: [{
|
|
960
1548
|
type: Input
|
|
961
1549
|
}], expandRowAriaLabel: [{
|
|
@@ -991,6 +1579,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
|
|
|
991
1579
|
}], exportButtonDir: [{
|
|
992
1580
|
type: ContentChild,
|
|
993
1581
|
args: [ExportButtonDirective]
|
|
1582
|
+
}], bodyScroller: [{
|
|
1583
|
+
type: ViewChild,
|
|
1584
|
+
args: ['bodyScroller']
|
|
1585
|
+
}], headerScroller: [{
|
|
1586
|
+
type: ViewChild,
|
|
1587
|
+
args: ['headerScroller']
|
|
994
1588
|
}], rowAdd: [{
|
|
995
1589
|
type: Output
|
|
996
1590
|
}], rowEdit: [{
|
|
@@ -1007,6 +1601,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
|
|
|
1007
1601
|
type: Output
|
|
1008
1602
|
}], pageChange: [{
|
|
1009
1603
|
type: Output
|
|
1604
|
+
}], selectionChange: [{
|
|
1605
|
+
type: Output
|
|
1010
1606
|
}], rowDetailTpl: [{
|
|
1011
1607
|
type: ContentChild,
|
|
1012
1608
|
args: [NgbRowDetailTemplate]
|
|
@@ -1043,10 +1639,10 @@ class NgbLiveAnnouncer {
|
|
|
1043
1639
|
}
|
|
1044
1640
|
this.node.textContent = message;
|
|
1045
1641
|
}
|
|
1046
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.
|
|
1047
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.
|
|
1642
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbLiveAnnouncer, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1643
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbLiveAnnouncer, providedIn: 'root' });
|
|
1048
1644
|
}
|
|
1049
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.
|
|
1645
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbLiveAnnouncer, decorators: [{
|
|
1050
1646
|
type: Injectable,
|
|
1051
1647
|
args: [{ providedIn: 'root' }]
|
|
1052
1648
|
}] });
|
|
@@ -1099,10 +1695,10 @@ class NgbDndState {
|
|
|
1099
1695
|
if (this.store.size === 0)
|
|
1100
1696
|
this.active.set(false);
|
|
1101
1697
|
}
|
|
1102
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.
|
|
1103
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.
|
|
1698
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbDndState, deps: [{ token: DND_LIVE_ANNOUNCE, optional: true }, { token: DND_I18N, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1699
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbDndState, providedIn: 'root' });
|
|
1104
1700
|
}
|
|
1105
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.
|
|
1701
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbDndState, decorators: [{
|
|
1106
1702
|
type: Injectable,
|
|
1107
1703
|
args: [{ providedIn: 'root' }]
|
|
1108
1704
|
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
@@ -1416,10 +2012,10 @@ class NgbDndListDirective {
|
|
|
1416
2012
|
});
|
|
1417
2013
|
this.state.announce?.(this.state.i18n.dropped());
|
|
1418
2014
|
}
|
|
1419
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.
|
|
1420
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.
|
|
2015
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbDndListDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2016
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.9", type: NgbDndListDirective, isStandalone: true, selector: "[ngbDndList]", inputs: { dndChildrenKey: "dndChildrenKey", list: ["ngbDndList", "list"], dndGroup: "dndGroup", dndDisabled: "dndDisabled", dndCloneOnDrop: "dndCloneOnDrop", dndCloneFn: "dndCloneFn", dndIsPalette: "dndIsPalette", dndCanDrop: "dndCanDrop", dndAriaLabel: "dndAriaLabel" }, outputs: { dndDropped: "dndDropped" }, host: { listeners: { "dragenter": "onDragEnter($event)", "dragover": "onDragOver($event)", "dragleave": "onDragLeave($event)", "document:drop": "onDocumentDrop($event)", "drop": "onDrop($event)" }, properties: { "class.ngb-dnd-denied": "this.denied", "attr.aria-label": "this.ariaLabel", "attr.role": "this.role", "class.ngb-dnd-list": "this.hostClass", "class.ngb-dnd-over": "this.isOver", "attr.data-drop-valid": "this.dataDropValid" } }, ngImport: i0 });
|
|
1421
2017
|
}
|
|
1422
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.
|
|
2018
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbDndListDirective, decorators: [{
|
|
1423
2019
|
type: Directive,
|
|
1424
2020
|
args: [{
|
|
1425
2021
|
selector: '[ngbDndList]',
|
|
@@ -1568,10 +2164,10 @@ class NgbDndItemDirective {
|
|
|
1568
2164
|
this.onDragEnd();
|
|
1569
2165
|
} // cancel
|
|
1570
2166
|
}
|
|
1571
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.
|
|
1572
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.
|
|
2167
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbDndItemDirective, deps: [{ token: NgbDndListDirective, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
|
|
2168
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.9", type: NgbDndItemDirective, isStandalone: true, selector: "[ngbDndItem]", inputs: { item: ["ngbDndItem", "item"], dndGroup: "dndGroup", dndIndex: "dndIndex", dndDisabled: "dndDisabled" }, outputs: { dndDragStart: "dndDragStart", dndDragEnd: "dndDragEnd" }, host: { listeners: { "dragstart": "onDragStart($event)", "dragend": "onDragEnd()", "keydown": "onKeydown($event)" }, properties: { "attr.draggable": "this.draggable", "class.ngb-dnd-dragging": "this.dragging", "attr.aria-grabbed": "this.ariaGrabbed", "attr.role": "this.role", "attr.tabindex": "this.tabIndex" } }, ngImport: i0 });
|
|
1573
2169
|
}
|
|
1574
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.
|
|
2170
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbDndItemDirective, decorators: [{
|
|
1575
2171
|
type: Directive,
|
|
1576
2172
|
args: [{
|
|
1577
2173
|
selector: '[ngbDndItem]',
|
|
@@ -1624,10 +2220,10 @@ class NgbStepLabelDirective {
|
|
|
1624
2220
|
constructor(template) {
|
|
1625
2221
|
this.template = template;
|
|
1626
2222
|
}
|
|
1627
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.
|
|
1628
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.
|
|
2223
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbStepLabelDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
|
|
2224
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.9", type: NgbStepLabelDirective, isStandalone: true, selector: "[ngbStepLabel]", inputs: { for: ["ngbStepLabel", "for"] }, ngImport: i0 });
|
|
1629
2225
|
}
|
|
1630
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.
|
|
2226
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbStepLabelDirective, decorators: [{
|
|
1631
2227
|
type: Directive,
|
|
1632
2228
|
args: [{
|
|
1633
2229
|
selector: '[ngbStepLabel]',
|
|
@@ -1822,10 +2418,10 @@ class NgbStepperComponent {
|
|
|
1822
2418
|
step: this.steps[nextIndex],
|
|
1823
2419
|
});
|
|
1824
2420
|
}
|
|
1825
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.
|
|
1826
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.
|
|
2421
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbStepperComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2422
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.9", type: NgbStepperComponent, isStandalone: true, selector: "ngb-stepper", inputs: { steps: "steps", orientation: "orientation", labelPosition: "labelPosition", contentPosition: "contentPosition", allowRevisit: "allowRevisit", lazy: "lazy", theme: "theme", responsive: "responsive", disableAnimation: "disableAnimation", animationDuration: "animationDuration", nextLabel: "nextLabel", previousLabel: "previousLabel", resetLabel: "resetLabel", cancelLabel: "cancelLabel", optionalLabel: "optionalLabel", stateIcons: "stateIcons", selectedIndex: "selectedIndex" }, outputs: { selectedIndexChange: "selectedIndexChange", selectionChange: "selectionChange", nextClicked: "nextClicked", prevClicked: "prevClicked", resetClicked: "resetClicked", cancelClicked: "cancelClicked" }, queries: [{ propertyName: "stepLabelTplDir", first: true, predicate: NgbStepLabelDirective, descendants: true }, { propertyName: "customIconTpl", first: true, predicate: ["ngbStepperIcon"], descendants: true, read: TemplateRef }, { propertyName: "stepContentTpl", first: true, predicate: ["stepContent"], descendants: true, read: TemplateRef }], ngImport: i0, template: "<div\n class=\"ngb-stepper\"\n [class.horizontal]=\"orientation === 'horizontal'\"\n [class.vertical]=\"orientation === 'vertical'\"\n [class.ngb-responsive]=\"responsive\"\n [class.bootstrap]=\"theme === 'bootstrap'\"\n [class.material]=\"theme === 'material'\"\n [class.tailwind]=\"theme === 'tailwind'\"\n role=\"tablist\"\n [attr.aria-orientation]=\"orientation\"\n>\n <!-- HEADER / LABELS -->\n <div class=\"ngb-stepper-header\">\n <ol class=\"ngb-stepper-steps\" role=\"presentation\">\n <li\n *ngFor=\"let step of steps; let i = index\"\n class=\"ngb-stepper-step\"\n [class.active]=\"i === selectedIndex\"\n [class.done]=\"i < selectedIndex && !isStepInError(i)\"\n [class.error]=\"isStepInError(i)\"\n [class.disabled]=\"step.disabled\"\n role=\"tab\"\n [attr.id]=\"stepId(i)\"\n [attr.aria-controls]=\"contentId(i)\"\n [attr.aria-selected]=\"i === selectedIndex\"\n [attr.aria-disabled]=\"step.disabled || (!allowRevisit && i < visitedFrom && i !== selectedIndex)\"\n tabindex=\"{{ i === selectedIndex ? 0 : -1 }}\"\n (click)=\"onHeaderClick(i)\"\n (keydown.enter)=\"onHeaderKeydown($event, i)\"\n (keydown.space)=\"onHeaderKeydown($event, i)\"\n >\n <div\n class=\"ngb-stepper-indicator\"\n [ngClass]=\"indicatorClass(i)\"\n aria-hidden=\"true\"\n >\n <ng-container *ngIf=\"customIconTpl; else defaultIcon\">\n <ng-container\n [ngTemplateOutlet]=\"customIconTpl\"\n [ngTemplateOutletContext]=\"{ index: i, state: stepState(i) }\"\n ></ng-container>\n </ng-container>\n <ng-template #defaultIcon>\n {{ defaultIconForState(stepState(i), i) }}\n </ng-template>\n </div>\n\n <div\n class=\"ngb-stepper-label-container\"\n [ngClass]=\"labelPositionClass\"\n >\n <div class=\"ngb-stepper-label\" *ngIf=\"stepLabelTpl; else textLabel\">\n <ng-container\n [ngTemplateOutlet]=\"stepLabelTpl\"\n [ngTemplateOutletContext]=\"{ index: i, step: step }\"\n ></ng-container>\n </div>\n <ng-template #textLabel>\n <div class=\"ngb-stepper-label-text\">\n {{ step.label || ('Step ' + (i + 1)) }}\n </div>\n </ng-template>\n <div class=\"ngb-stepper-optional\" *ngIf=\"step.optional\">\n {{ optionalLabel }}\n </div>\n </div>\n </li>\n </ol>\n </div>\n\n <!-- CONTENT -->\n <div class=\"ngb-stepper-content\" [class.ngb-stepper-content-top]=\"contentPosition === 'top'\">\n <ng-container *ngIf=\"lazy; else allContent\">\n <ng-container *ngFor=\"let index of [selectedIndex]\">\n <div\n class=\"fade-step\"\n [style.--ngb-stepper-animation-duration]=\"(disableAnimation ? 0 : animationDuration) + 'ms'\"\n role=\"tabpanel\"\n [attr.aria-labelledby]=\"stepId(index)\"\n [attr.id]=\"contentId(index)\"\n >\n <ng-container *ngTemplateOutlet=\"stepContentTpl; context: { index: index }\"></ng-container>\n <div\n *ngIf=\"currentErrorMessage\"\n class=\"ngb-stepper-error\"\n role=\"alert\"\n >\n {{ currentErrorMessage }}\n </div>\n </div>\n </ng-container>\n </ng-container>\n\n <ng-template #allContent>\n <div\n class=\"fade-step\"\n [style.--ngb-stepper-animation-duration]=\"(disableAnimation ? 0 : animationDuration) + 'ms'\"\n role=\"tabpanel\"\n [attr.aria-labelledby]=\"stepId(selectedIndex)\"\n [attr.id]=\"contentId(selectedIndex)\"\n >\n <ng-container *ngTemplateOutlet=\"stepContentTpl; context: { index: selectedIndex }\"></ng-container>\n <div\n *ngIf=\"currentErrorMessage\"\n class=\"ngb-stepper-error\"\n role=\"alert\"\n >\n {{ currentErrorMessage }}\n </div>\n </div>\n </ng-template>\n </div>\n\n <!-- ACTIONS -->\n <div class=\"ngb-stepper-buttons\">\n <button\n type=\"button\"\n class=\"btn btn-sm btn-outline-secondary\"\n (click)=\"onCancel()\"\n >\n {{ cancelLabel }}\n </button>\n\n <button\n type=\"button\"\n class=\"btn btn-sm btn-outline-secondary\"\n (click)=\"onReset()\"\n >\n {{ resetLabel }}\n </button>\n\n <button\n type=\"button\"\n class=\"btn btn-sm btn-outline-secondary\"\n (click)=\"prev()\"\n [disabled]=\"selectedIndex <= 0 || !allowRevisit\"\n >\n {{ previousLabel }}\n </button>\n\n <button\n type=\"button\"\n class=\"btn btn-sm btn-primary\"\n (click)=\"next()\"\n [disabled]=\"selectedIndex >= steps.length - 1 || steps[selectedIndex]?.disabled\"\n >\n {{ nextLabel }}\n </button>\n </div>\n</div>\n", styles: [".ngb-stepper{display:flex;flex-direction:column}.ngb-stepper.horizontal .ngb-stepper-header{display:flex;overflow-x:auto}.ngb-stepper.vertical .ngb-stepper-header{display:block}.ngb-stepper-header{margin-bottom:1rem}.ngb-stepper-steps{list-style:none;padding:0;margin:0;display:flex;flex-wrap:nowrap}.ngb-stepper.vertical .ngb-stepper-steps{flex-direction:column}.ngb-stepper-step{position:relative;display:flex;align-items:center;cursor:pointer}.ngb-stepper.horizontal .ngb-stepper-step{padding:.5rem .75rem}.ngb-stepper.vertical .ngb-stepper-step{padding:.5rem 0}.ngb-stepper-step.disabled{cursor:default;opacity:.6}.ngb-stepper-indicator{display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border-radius:50%;margin-right:.5rem;flex-shrink:0}.ngb-stepper.bootstrap .ngb-stepper-indicator{border:1px solid var(--bs-border-color, #dee2e6);background-color:var(--bs-body-bg, #fff)}.ngb-stepper.bootstrap .ngb-stepper-step.active .ngb-stepper-indicator{background-color:var(--bs-primary, #0d6efd);color:#fff}.ngb-stepper.bootstrap .ngb-stepper-step.done .ngb-stepper-indicator{background-color:var(--bs-success, #198754);color:#fff}.ngb-stepper.bootstrap .ngb-stepper-step.error .ngb-stepper-indicator{background-color:var(--bs-danger, #dc3545);color:#fff}.ngb-stepper-label-container{display:flex;flex-direction:column}.ngb-stepper-label-top{flex-direction:column-reverse}.ngb-stepper-label-bottom{flex-direction:column}.ngb-stepper-label-left{flex-direction:row-reverse}.ngb-stepper-label-right{flex-direction:row}.ngb-stepper-content{position:relative}.ngb-stepper-content-top{order:-1}.ngb-stepper-buttons{display:flex;justify-content:flex-end;gap:.5rem;margin-top:1rem}.ngb-stepper-error{color:var(--bs-danger, #dc3545);font-size:.875rem;margin-top:.25rem}.ngb-stepper-optional{font-size:.75rem;opacity:.7}.ngb-stepper .fade-step{animation:ngb-stepper-fade var(--ngb-stepper-animation-duration, .15s) ease-in-out;animation-fill-mode:both}@keyframes ngb-stepper-fade{0%{opacity:0;transform:translateY(.35rem)}to{opacity:1;transform:translateY(0)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1827
2423
|
}
|
|
1828
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.
|
|
2424
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbStepperComponent, decorators: [{
|
|
1829
2425
|
type: Component,
|
|
1830
2426
|
args: [{ selector: 'ngb-stepper', standalone: true, imports: [CommonModule, NgbStepLabelDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n class=\"ngb-stepper\"\n [class.horizontal]=\"orientation === 'horizontal'\"\n [class.vertical]=\"orientation === 'vertical'\"\n [class.ngb-responsive]=\"responsive\"\n [class.bootstrap]=\"theme === 'bootstrap'\"\n [class.material]=\"theme === 'material'\"\n [class.tailwind]=\"theme === 'tailwind'\"\n role=\"tablist\"\n [attr.aria-orientation]=\"orientation\"\n>\n <!-- HEADER / LABELS -->\n <div class=\"ngb-stepper-header\">\n <ol class=\"ngb-stepper-steps\" role=\"presentation\">\n <li\n *ngFor=\"let step of steps; let i = index\"\n class=\"ngb-stepper-step\"\n [class.active]=\"i === selectedIndex\"\n [class.done]=\"i < selectedIndex && !isStepInError(i)\"\n [class.error]=\"isStepInError(i)\"\n [class.disabled]=\"step.disabled\"\n role=\"tab\"\n [attr.id]=\"stepId(i)\"\n [attr.aria-controls]=\"contentId(i)\"\n [attr.aria-selected]=\"i === selectedIndex\"\n [attr.aria-disabled]=\"step.disabled || (!allowRevisit && i < visitedFrom && i !== selectedIndex)\"\n tabindex=\"{{ i === selectedIndex ? 0 : -1 }}\"\n (click)=\"onHeaderClick(i)\"\n (keydown.enter)=\"onHeaderKeydown($event, i)\"\n (keydown.space)=\"onHeaderKeydown($event, i)\"\n >\n <div\n class=\"ngb-stepper-indicator\"\n [ngClass]=\"indicatorClass(i)\"\n aria-hidden=\"true\"\n >\n <ng-container *ngIf=\"customIconTpl; else defaultIcon\">\n <ng-container\n [ngTemplateOutlet]=\"customIconTpl\"\n [ngTemplateOutletContext]=\"{ index: i, state: stepState(i) }\"\n ></ng-container>\n </ng-container>\n <ng-template #defaultIcon>\n {{ defaultIconForState(stepState(i), i) }}\n </ng-template>\n </div>\n\n <div\n class=\"ngb-stepper-label-container\"\n [ngClass]=\"labelPositionClass\"\n >\n <div class=\"ngb-stepper-label\" *ngIf=\"stepLabelTpl; else textLabel\">\n <ng-container\n [ngTemplateOutlet]=\"stepLabelTpl\"\n [ngTemplateOutletContext]=\"{ index: i, step: step }\"\n ></ng-container>\n </div>\n <ng-template #textLabel>\n <div class=\"ngb-stepper-label-text\">\n {{ step.label || ('Step ' + (i + 1)) }}\n </div>\n </ng-template>\n <div class=\"ngb-stepper-optional\" *ngIf=\"step.optional\">\n {{ optionalLabel }}\n </div>\n </div>\n </li>\n </ol>\n </div>\n\n <!-- CONTENT -->\n <div class=\"ngb-stepper-content\" [class.ngb-stepper-content-top]=\"contentPosition === 'top'\">\n <ng-container *ngIf=\"lazy; else allContent\">\n <ng-container *ngFor=\"let index of [selectedIndex]\">\n <div\n class=\"fade-step\"\n [style.--ngb-stepper-animation-duration]=\"(disableAnimation ? 0 : animationDuration) + 'ms'\"\n role=\"tabpanel\"\n [attr.aria-labelledby]=\"stepId(index)\"\n [attr.id]=\"contentId(index)\"\n >\n <ng-container *ngTemplateOutlet=\"stepContentTpl; context: { index: index }\"></ng-container>\n <div\n *ngIf=\"currentErrorMessage\"\n class=\"ngb-stepper-error\"\n role=\"alert\"\n >\n {{ currentErrorMessage }}\n </div>\n </div>\n </ng-container>\n </ng-container>\n\n <ng-template #allContent>\n <div\n class=\"fade-step\"\n [style.--ngb-stepper-animation-duration]=\"(disableAnimation ? 0 : animationDuration) + 'ms'\"\n role=\"tabpanel\"\n [attr.aria-labelledby]=\"stepId(selectedIndex)\"\n [attr.id]=\"contentId(selectedIndex)\"\n >\n <ng-container *ngTemplateOutlet=\"stepContentTpl; context: { index: selectedIndex }\"></ng-container>\n <div\n *ngIf=\"currentErrorMessage\"\n class=\"ngb-stepper-error\"\n role=\"alert\"\n >\n {{ currentErrorMessage }}\n </div>\n </div>\n </ng-template>\n </div>\n\n <!-- ACTIONS -->\n <div class=\"ngb-stepper-buttons\">\n <button\n type=\"button\"\n class=\"btn btn-sm btn-outline-secondary\"\n (click)=\"onCancel()\"\n >\n {{ cancelLabel }}\n </button>\n\n <button\n type=\"button\"\n class=\"btn btn-sm btn-outline-secondary\"\n (click)=\"onReset()\"\n >\n {{ resetLabel }}\n </button>\n\n <button\n type=\"button\"\n class=\"btn btn-sm btn-outline-secondary\"\n (click)=\"prev()\"\n [disabled]=\"selectedIndex <= 0 || !allowRevisit\"\n >\n {{ previousLabel }}\n </button>\n\n <button\n type=\"button\"\n class=\"btn btn-sm btn-primary\"\n (click)=\"next()\"\n [disabled]=\"selectedIndex >= steps.length - 1 || steps[selectedIndex]?.disabled\"\n >\n {{ nextLabel }}\n </button>\n </div>\n</div>\n", styles: [".ngb-stepper{display:flex;flex-direction:column}.ngb-stepper.horizontal .ngb-stepper-header{display:flex;overflow-x:auto}.ngb-stepper.vertical .ngb-stepper-header{display:block}.ngb-stepper-header{margin-bottom:1rem}.ngb-stepper-steps{list-style:none;padding:0;margin:0;display:flex;flex-wrap:nowrap}.ngb-stepper.vertical .ngb-stepper-steps{flex-direction:column}.ngb-stepper-step{position:relative;display:flex;align-items:center;cursor:pointer}.ngb-stepper.horizontal .ngb-stepper-step{padding:.5rem .75rem}.ngb-stepper.vertical .ngb-stepper-step{padding:.5rem 0}.ngb-stepper-step.disabled{cursor:default;opacity:.6}.ngb-stepper-indicator{display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border-radius:50%;margin-right:.5rem;flex-shrink:0}.ngb-stepper.bootstrap .ngb-stepper-indicator{border:1px solid var(--bs-border-color, #dee2e6);background-color:var(--bs-body-bg, #fff)}.ngb-stepper.bootstrap .ngb-stepper-step.active .ngb-stepper-indicator{background-color:var(--bs-primary, #0d6efd);color:#fff}.ngb-stepper.bootstrap .ngb-stepper-step.done .ngb-stepper-indicator{background-color:var(--bs-success, #198754);color:#fff}.ngb-stepper.bootstrap .ngb-stepper-step.error .ngb-stepper-indicator{background-color:var(--bs-danger, #dc3545);color:#fff}.ngb-stepper-label-container{display:flex;flex-direction:column}.ngb-stepper-label-top{flex-direction:column-reverse}.ngb-stepper-label-bottom{flex-direction:column}.ngb-stepper-label-left{flex-direction:row-reverse}.ngb-stepper-label-right{flex-direction:row}.ngb-stepper-content{position:relative}.ngb-stepper-content-top{order:-1}.ngb-stepper-buttons{display:flex;justify-content:flex-end;gap:.5rem;margin-top:1rem}.ngb-stepper-error{color:var(--bs-danger, #dc3545);font-size:.875rem;margin-top:.25rem}.ngb-stepper-optional{font-size:.75rem;opacity:.7}.ngb-stepper .fade-step{animation:ngb-stepper-fade var(--ngb-stepper-animation-duration, .15s) ease-in-out;animation-fill-mode:both}@keyframes ngb-stepper-fade{0%{opacity:0;transform:translateY(.35rem)}to{opacity:1;transform:translateY(0)}}\n"] }]
|
|
1831
2427
|
}], propDecorators: { steps: [{
|
|
@@ -1894,14 +2490,14 @@ class NgbSplitterPaneComponent {
|
|
|
1894
2490
|
collapsed = false;
|
|
1895
2491
|
collapsedChange = new EventEmitter();
|
|
1896
2492
|
template;
|
|
1897
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.
|
|
1898
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.
|
|
2493
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbSplitterPaneComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2494
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.9", type: NgbSplitterPaneComponent, isStandalone: true, selector: "ngb-splitter-pane", inputs: { size: "size", min: "min", max: "max", scrollable: "scrollable", collapsible: "collapsible", collapsed: "collapsed" }, outputs: { collapsedChange: "collapsedChange" }, viewQueries: [{ propertyName: "template", first: true, predicate: ["content"], descendants: true, static: true }], ngImport: i0, template: `<ng-template #content>
|
|
1899
2495
|
<div [style.overflow]="scrollable ? 'auto' : 'hidden'" style="height: 100%; width: 100%;">
|
|
1900
2496
|
<ng-content></ng-content>
|
|
1901
2497
|
</div>
|
|
1902
2498
|
</ng-template>`, isInline: true, styles: [":host{display:block;position:relative}\n"] });
|
|
1903
2499
|
}
|
|
1904
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.
|
|
2500
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbSplitterPaneComponent, decorators: [{
|
|
1905
2501
|
type: Component,
|
|
1906
2502
|
args: [{ selector: 'ngb-splitter-pane', standalone: true, template: `<ng-template #content>
|
|
1907
2503
|
<div [style.overflow]="scrollable ? 'auto' : 'hidden'" style="height: 100%; width: 100%;">
|
|
@@ -2133,8 +2729,8 @@ class NgbSplitterComponent {
|
|
|
2133
2729
|
nextPercent = Math.max(0, Math.min(100, nextPercent));
|
|
2134
2730
|
targetPane.size = `${nextPercent}%`;
|
|
2135
2731
|
}
|
|
2136
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.
|
|
2137
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.
|
|
2732
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbSplitterComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
2733
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.9", type: NgbSplitterComponent, isStandalone: true, selector: "ngb-splitter", inputs: { orientation: "orientation", handleThickness: "handleThickness", handleIconColor: "handleIconColor", verticalMinHeight: "verticalMinHeight", resizable: "resizable", barColor: "barColor", lineColor: "lineColor" }, host: { listeners: { "window:mousemove": "onMouseMove($event)", "window:mouseup": "onMouseUp()" } }, queries: [{ propertyName: "panes", predicate: NgbSplitterPaneComponent }], ngImport: i0, template: `
|
|
2138
2734
|
<div class="splitter-container" [class.vertical]="orientation === 'vertical'"
|
|
2139
2735
|
[style.min-height]="orientation === 'vertical' ? verticalMinHeight : null"
|
|
2140
2736
|
[style.height]="orientation === 'vertical' ? verticalMinHeight : null">
|
|
@@ -2178,7 +2774,7 @@ class NgbSplitterComponent {
|
|
|
2178
2774
|
</div>
|
|
2179
2775
|
`, isInline: true, styles: [":host{display:block;width:100%}.splitter-container{display:flex;height:100%;width:100%}.splitter-container.vertical{flex-direction:column}.splitbar{background:#ccc;width:5px;position:relative;align-items:center;justify-content:center;flex:0 0 auto;z-index:10}.splitbar.resizable{cursor:col-resize}.splitbar:hover{filter:brightness(90%)}.handle-line{border-radius:2px;opacity:.8;left:45%;position:absolute;top:45%;display:flex;align-items:center;justify-content:center}.splitter-container:not(.vertical) .handle-line{width:2px;height:10px}.pane-wrapper{position:relative;min-width:0;min-height:0;overflow:hidden;flex-shrink:1}.vertical .handle-line{height:2px;width:10px}.vertical .splitbar.resizable{cursor:row-resize}.splitter-container.vertical .splitter-container .splitbar.resizable{cursor:col-resize}.vertical .splitbar{width:100%}.collapse-btn{cursor:pointer;background:#666;width:10px;height:10px;position:absolute;top:50%}.collapse-arrow{font-size:.95rem;-webkit-user-select:none;user-select:none;cursor:pointer;line-height:1;display:inline-flex;align-items:center;justify-content:center;width:1.25rem;height:1.25rem;position:absolute;top:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2180
2776
|
}
|
|
2181
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.
|
|
2777
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbSplitterComponent, decorators: [{
|
|
2182
2778
|
type: Component,
|
|
2183
2779
|
args: [{ selector: 'ngb-splitter', standalone: true, imports: [CommonModule, NgbSplitterPaneComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
2184
2780
|
<div class="splitter-container" [class.vertical]="orientation === 'vertical'"
|
|
@@ -2255,8 +2851,8 @@ class NgbChipsComponent {
|
|
|
2255
2851
|
removeLabel;
|
|
2256
2852
|
remove = new EventEmitter();
|
|
2257
2853
|
trackById = (_, item) => item.id;
|
|
2258
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.
|
|
2259
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.
|
|
2854
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbChipsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2855
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.9", type: NgbChipsComponent, isStandalone: true, selector: "ngb-chips", inputs: { items: "items", removable: "removable", ariaLabel: "ariaLabel", removeLabel: "removeLabel" }, outputs: { remove: "remove" }, ngImport: i0, template: `
|
|
2260
2856
|
<div class="ngb-chips" [attr.aria-label]="ariaLabel">
|
|
2261
2857
|
<span
|
|
2262
2858
|
*ngFor="let item of items; trackBy: trackById"
|
|
@@ -2278,7 +2874,7 @@ class NgbChipsComponent {
|
|
|
2278
2874
|
</div>
|
|
2279
2875
|
`, isInline: true, styles: [":host{display:block}.ngb-chips{display:flex;flex-wrap:wrap;gap:.35rem;align-items:center}.ngb-chip{display:inline-flex;align-items:center;gap:.25rem;max-width:100%}.ngb-chip-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ngb-chip-remove{border:0;background:transparent;padding:0;line-height:1;cursor:pointer;font-size:1rem;opacity:.85}.ngb-chip-remove:disabled{cursor:default;opacity:.4}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2280
2876
|
}
|
|
2281
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.
|
|
2877
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbChipsComponent, decorators: [{
|
|
2282
2878
|
type: Component,
|
|
2283
2879
|
args: [{ selector: 'ngb-chips', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
2284
2880
|
<div class="ngb-chips" [attr.aria-label]="ariaLabel">
|
|
@@ -3013,8 +3609,8 @@ class NgbTypeaheadComponent {
|
|
|
3013
3609
|
return match;
|
|
3014
3610
|
return { id: `${value}`, label: `${value}`, value };
|
|
3015
3611
|
}
|
|
3016
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.
|
|
3017
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.
|
|
3612
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbTypeaheadComponent, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
3613
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.9", type: NgbTypeaheadComponent, isStandalone: true, selector: "ngb-typeahead", inputs: { data: "data", debounceTime: "debounceTime", characterTyped: "characterTyped", limit: "limit", selectExact: "selectExact", multiSelect: "multiSelect", matchSelection: "matchSelection", showDropdownButton: "showDropdownButton", showClearButton: "showClearButton", updateOnBlur: "updateOnBlur", updateOnTab: "updateOnTab", separator: "separator", chips: "chips", vScroll: "vScroll", vItemSize: "vItemSize", itemTemplate: "itemTemplate", i18n: "i18n" }, outputs: { completeMethod: "completeMethod", onSelect: "onSelect", onUnselect: "onUnselect", onAdd: "onAdd", onFocus: "onFocus", onBlur: "onBlur", onDropdownClick: "onDropdownClick", onClear: "onClear", onInputKeydown: "onInputKeydown", onKeyUp: "onKeyUp", onShow: "onShow", onHide: "onHide", onLazyLoad: "onLazyLoad", selectedItems: "selectedItems", selectionChange: "selectionChange", onChange: "onChange", onScrollEvent: "onScrollEvent" }, host: { listeners: { "document:mousedown": "onDocumentMouseDown($event)", "document:focusin": "onDocumentFocusIn($event)" } }, providers: [
|
|
3018
3614
|
{
|
|
3019
3615
|
provide: NG_VALUE_ACCESSOR,
|
|
3020
3616
|
useExisting: forwardRef(() => NgbTypeaheadComponent),
|
|
@@ -3160,7 +3756,7 @@ class NgbTypeaheadComponent {
|
|
|
3160
3756
|
</div>
|
|
3161
3757
|
`, isInline: true, styles: [":host{display:block}.typeahead-root{position:relative}.typeahead-chips-control{display:flex;flex-wrap:wrap;align-items:center;gap:.35rem;min-height:calc(1.5em + .75rem + 2px);padding:.375rem .75rem}.typeahead-chips-control input{border:0;outline:0;flex:1 1 9rem;min-width:6rem;padding:0;margin:0;background:transparent}.typeahead-chips-control input:focus{outline:0;box-shadow:none}.typeahead-panel{position:absolute;top:calc(100% + .25rem);left:0;right:0;z-index:1050;max-height:240px;overflow:auto;opacity:0;transform:translateY(-.25rem);pointer-events:none;transition:opacity .12s ease,transform .12s ease}.typeahead-panel.show{opacity:1;transform:translateY(0);pointer-events:auto}.typeahead-item{display:flex;align-items:center;gap:.5rem}.typeahead-item-checkbox{display:inline-flex;align-items:center;justify-content:center;width:1.15rem;height:1.15rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: NgbChipsComponent, selector: "ngb-chips", inputs: ["items", "removable", "ariaLabel", "removeLabel"], outputs: ["remove"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3162
3758
|
}
|
|
3163
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.
|
|
3759
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbTypeaheadComponent, decorators: [{
|
|
3164
3760
|
type: Component,
|
|
3165
3761
|
args: [{ selector: 'ngb-typeahead', standalone: true, imports: [CommonModule, NgbChipsComponent], providers: [
|
|
3166
3762
|
{
|
|
@@ -3483,8 +4079,8 @@ class NgbTreeComponent {
|
|
|
3483
4079
|
}
|
|
3484
4080
|
return acc;
|
|
3485
4081
|
}
|
|
3486
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.
|
|
3487
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.
|
|
4082
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbTreeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4083
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.9", type: NgbTreeComponent, isStandalone: true, selector: "ngb-tree", inputs: { nodes: "nodes", type: "type", showCheckbox: "showCheckbox", i18n: "i18n", expandIcon: "expandIcon", collapseIcon: "collapseIcon", plusIcon: "plusIcon", minusIcon: "minusIcon" }, outputs: { expand: "expand", collapse: "collapse", expandAll: "expandAll", collapseAll: "collapseAll", selectionChange: "selectionChange" }, viewQueries: [{ propertyName: "nodeButtons", predicate: ["nodeBtn"], descendants: true, read: ElementRef }], ngImport: i0, template: `
|
|
3488
4084
|
<div class="d-flex gap-2 mb-2">
|
|
3489
4085
|
<button type="button" class="btn btn-sm btn-outline-secondary" (click)="expandAllNodes()" [attr.aria-label]="i18n?.expandAll || 'Expand all'">
|
|
3490
4086
|
{{ i18n?.expandAll || 'Expand all' }}
|
|
@@ -3550,7 +4146,7 @@ class NgbTreeComponent {
|
|
|
3550
4146
|
</ng-template>
|
|
3551
4147
|
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3552
4148
|
}
|
|
3553
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.
|
|
4149
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbTreeComponent, decorators: [{
|
|
3554
4150
|
type: Component,
|
|
3555
4151
|
args: [{
|
|
3556
4152
|
selector: 'ngb-tree',
|