@angular-bootstrap/ngbootstrap 0.0.11 → 0.0.13
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,10 +1,10 @@
|
|
|
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';
|
|
6
6
|
import { FormBuilder, FormControl, Validators, FormsModule, ReactiveFormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
7
|
-
import {
|
|
7
|
+
import { isObservable, firstValueFrom } from 'rxjs';
|
|
8
8
|
|
|
9
9
|
class NgbCellTemplate {
|
|
10
10
|
template;
|
|
@@ -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,313 @@ 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
|
+
const CHROME_TOLERANCE = 12; // small buffer to ignore reapplication of padding/borders
|
|
381
|
+
class NgbSyncColgroupDirective {
|
|
382
|
+
el;
|
|
383
|
+
syncId;
|
|
384
|
+
syncRole = 'header';
|
|
385
|
+
static registry = new Map();
|
|
386
|
+
mutationObserver;
|
|
387
|
+
resizeObserver;
|
|
388
|
+
rafId = null;
|
|
389
|
+
constructor(el) {
|
|
390
|
+
this.el = el;
|
|
391
|
+
}
|
|
392
|
+
ngAfterViewInit() {
|
|
393
|
+
if (!this.syncId)
|
|
394
|
+
return;
|
|
395
|
+
const entry = this.ensureEntry();
|
|
396
|
+
if (this.syncRole === 'header') {
|
|
397
|
+
entry.header = this;
|
|
398
|
+
this.measureAndDistribute();
|
|
399
|
+
}
|
|
400
|
+
else {
|
|
401
|
+
entry.bodies.add(this);
|
|
402
|
+
if (entry.header)
|
|
403
|
+
entry.header.measureAndDistribute();
|
|
404
|
+
if (entry.widths?.length)
|
|
405
|
+
this.apply(entry.widths);
|
|
406
|
+
this.startObservers();
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
ngOnDestroy() {
|
|
410
|
+
if (!this.syncId)
|
|
411
|
+
return;
|
|
412
|
+
if (this.rafId != null)
|
|
413
|
+
cancelAnimationFrame(this.rafId);
|
|
414
|
+
this.mutationObserver?.disconnect();
|
|
415
|
+
this.resizeObserver?.disconnect();
|
|
416
|
+
const entry = NgbSyncColgroupDirective.registry.get(this.syncId);
|
|
417
|
+
if (!entry)
|
|
418
|
+
return;
|
|
419
|
+
if (entry.header === this)
|
|
420
|
+
entry.header = undefined;
|
|
421
|
+
entry.bodies.delete(this);
|
|
422
|
+
if (!entry.header && entry.bodies.size === 0) {
|
|
423
|
+
NgbSyncColgroupDirective.registry.delete(this.syncId);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
onResize() {
|
|
427
|
+
if (this.syncRole === 'header')
|
|
428
|
+
this.measureAndDistribute();
|
|
429
|
+
}
|
|
430
|
+
measureAndDistribute() {
|
|
431
|
+
const widths = this.measure();
|
|
432
|
+
if (!widths.length)
|
|
433
|
+
return;
|
|
434
|
+
const entry = this.ensureEntry();
|
|
435
|
+
if (entry.widths && this.areWidthsEqual(entry.widths, widths))
|
|
436
|
+
return;
|
|
437
|
+
entry.widths = widths;
|
|
438
|
+
this.apply(widths);
|
|
439
|
+
entry.bodies.forEach(b => b.apply(widths));
|
|
440
|
+
}
|
|
441
|
+
ensureEntry() {
|
|
442
|
+
let entry = NgbSyncColgroupDirective.registry.get(this.syncId);
|
|
443
|
+
if (!entry) {
|
|
444
|
+
entry = { bodies: new Set() };
|
|
445
|
+
NgbSyncColgroupDirective.registry.set(this.syncId, entry);
|
|
446
|
+
}
|
|
447
|
+
return entry;
|
|
448
|
+
}
|
|
449
|
+
startObservers() {
|
|
450
|
+
const bodyTable = this.tableEl();
|
|
451
|
+
const tbody = bodyTable?.querySelector('tbody');
|
|
452
|
+
if (tbody && typeof MutationObserver !== 'undefined') {
|
|
453
|
+
this.mutationObserver = new MutationObserver(() => this.scheduleMeasure());
|
|
454
|
+
this.mutationObserver.observe(tbody, { childList: true, subtree: true, characterData: true });
|
|
455
|
+
}
|
|
456
|
+
if (bodyTable && typeof ResizeObserver !== 'undefined') {
|
|
457
|
+
this.resizeObserver = new ResizeObserver(() => this.scheduleMeasure());
|
|
458
|
+
this.resizeObserver.observe(bodyTable);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
scheduleMeasure() {
|
|
462
|
+
if (this.rafId != null)
|
|
463
|
+
return;
|
|
464
|
+
this.rafId = requestAnimationFrame(() => {
|
|
465
|
+
this.rafId = null;
|
|
466
|
+
const entry = NgbSyncColgroupDirective.registry.get(this.syncId);
|
|
467
|
+
entry?.header?.measureAndDistribute();
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
colElements() {
|
|
471
|
+
return Array.from(this.el.nativeElement.querySelectorAll('col'));
|
|
472
|
+
}
|
|
473
|
+
tableEl() {
|
|
474
|
+
return this.el.nativeElement.closest('table');
|
|
475
|
+
}
|
|
476
|
+
firstBodyForSync() {
|
|
477
|
+
const entry = NgbSyncColgroupDirective.registry.get(this.syncId);
|
|
478
|
+
const bodyDir = this.syncRole === 'body'
|
|
479
|
+
? this
|
|
480
|
+
: entry ? Array.from(entry.bodies.values())[0] : undefined;
|
|
481
|
+
return bodyDir?.tableEl() ?? null;
|
|
482
|
+
}
|
|
483
|
+
measure() {
|
|
484
|
+
const bodyTable = this.firstBodyForSync();
|
|
485
|
+
const cols = this.colElements();
|
|
486
|
+
const entry = NgbSyncColgroupDirective.registry.get(this.syncId);
|
|
487
|
+
if (!cols.length)
|
|
488
|
+
return [];
|
|
489
|
+
if (!bodyTable) {
|
|
490
|
+
return entry?.widths ?? [];
|
|
491
|
+
}
|
|
492
|
+
const bodyRows = Array.from(bodyTable.querySelectorAll('tbody tr')).slice(0, MAX_SAMPLE_ROWS);
|
|
493
|
+
const headerTable = this.syncRole === 'header' ? this.tableEl() : null;
|
|
494
|
+
const headerRow = headerTable?.querySelector('thead tr');
|
|
495
|
+
return cols.map((col, colIndex) => {
|
|
496
|
+
const fixedWidth = (col.getAttribute('data-fixed') ?? '').toLowerCase() === 'true';
|
|
497
|
+
if (fixedWidth) {
|
|
498
|
+
const explicit = parseFloat(col.style.width || '') || MIN_WIDTH;
|
|
499
|
+
return Math.min(Math.max(explicit, MIN_WIDTH), MAX_WIDTH);
|
|
500
|
+
}
|
|
501
|
+
// Measure header content width if available
|
|
502
|
+
let headerContentWidth = 0;
|
|
503
|
+
if (headerRow) {
|
|
504
|
+
const th = headerRow.querySelectorAll('th')[colIndex];
|
|
505
|
+
if (th) {
|
|
506
|
+
headerContentWidth = this.measureCellContent(th);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
// Measure body content width
|
|
510
|
+
let maxContent = 0;
|
|
511
|
+
for (const tr of bodyRows) {
|
|
512
|
+
const td = tr.querySelectorAll('td')[colIndex];
|
|
513
|
+
if (!td)
|
|
514
|
+
continue;
|
|
515
|
+
maxContent = Math.max(maxContent, this.measureCellContent(td));
|
|
516
|
+
if (maxContent >= MAX_WIDTH)
|
|
517
|
+
break;
|
|
518
|
+
}
|
|
519
|
+
// Use the maximum of header and body content widths
|
|
520
|
+
let finalContent = Math.max(headerContentWidth, maxContent);
|
|
521
|
+
if (finalContent === 0)
|
|
522
|
+
finalContent = MIN_WIDTH;
|
|
523
|
+
let width = Math.min(Math.max(finalContent, MIN_WIDTH), MAX_WIDTH);
|
|
524
|
+
const prev = entry?.widths?.[colIndex];
|
|
525
|
+
if (prev && width > prev) {
|
|
526
|
+
// If the only change is re-adding cell chrome (common when interactive elements span the cell),
|
|
527
|
+
// keep the previous stable width to avoid incremental growth.
|
|
528
|
+
const delta = width - prev;
|
|
529
|
+
if (delta <= CHROME_TOLERANCE)
|
|
530
|
+
width = prev;
|
|
531
|
+
}
|
|
532
|
+
return width;
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
apply(widths) {
|
|
536
|
+
const cols = this.colElements();
|
|
537
|
+
widths.forEach((w, i) => {
|
|
538
|
+
const col = cols[i];
|
|
539
|
+
if (!col)
|
|
540
|
+
return;
|
|
541
|
+
col.style.width = w ? `${w}px` : '';
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
measureCellContent(cell) {
|
|
545
|
+
const style = getComputedStyle(cell);
|
|
546
|
+
const cellClientWidth = cell.clientWidth;
|
|
547
|
+
const cellRect = cell.getBoundingClientRect();
|
|
548
|
+
const chrome = (parseFloat(style.paddingLeft) || 0) +
|
|
549
|
+
(parseFloat(style.paddingRight) || 0) +
|
|
550
|
+
(parseFloat(style.borderLeftWidth) || 0) +
|
|
551
|
+
(parseFloat(style.borderRightWidth) || 0);
|
|
552
|
+
const interactiveEls = Array.from(cell.querySelectorAll('input, select, textarea, button'));
|
|
553
|
+
let interactiveWidth = null;
|
|
554
|
+
if (interactiveEls.length) {
|
|
555
|
+
interactiveWidth = interactiveEls.reduce((total, el) => {
|
|
556
|
+
const rect = el.getBoundingClientRect();
|
|
557
|
+
const elStyle = getComputedStyle(el);
|
|
558
|
+
const widthStr = (el.style.width || elStyle.width || '').toString().trim();
|
|
559
|
+
const usesPercentWidth = widthStr.endsWith('%');
|
|
560
|
+
const matchesCellWidth = (!!cellClientWidth && rect.width && Math.abs(rect.width - cellClientWidth) <= 1) ||
|
|
561
|
+
(cellRect.width > 0 && rect.width > 0 && Math.abs(rect.width - cellRect.width) <= 1);
|
|
562
|
+
const spansCell = usesPercentWidth || matchesCellWidth;
|
|
563
|
+
const margin = (parseFloat(elStyle.marginLeft) || 0) + (parseFloat(elStyle.marginRight) || 0);
|
|
564
|
+
if (spansCell) {
|
|
565
|
+
const textWidth = this.measureTextWidth((el.textContent ?? '').trim(), elStyle);
|
|
566
|
+
const paddingBorder = (parseFloat(elStyle.paddingLeft) || 0) +
|
|
567
|
+
(parseFloat(elStyle.paddingRight) || 0) +
|
|
568
|
+
(parseFloat(elStyle.borderLeftWidth) || 0) +
|
|
569
|
+
(parseFloat(elStyle.borderRightWidth) || 0);
|
|
570
|
+
return total + Math.ceil(textWidth + paddingBorder + margin);
|
|
571
|
+
}
|
|
572
|
+
const rectWidth = rect.width || parseFloat(elStyle.width) || ((el.textContent ?? '').length * ((parseFloat(elStyle.fontSize) || 14) * CHAR_WIDTH_FACTOR));
|
|
573
|
+
return total + rectWidth + margin;
|
|
574
|
+
}, 0);
|
|
575
|
+
interactiveWidth = Math.ceil((interactiveWidth || 0) + chrome);
|
|
576
|
+
}
|
|
577
|
+
const text = (cell.textContent ?? '').trim();
|
|
578
|
+
const textWidth = Math.ceil(this.measureTextWidth(text, style) + chrome);
|
|
579
|
+
if (interactiveWidth != null) {
|
|
580
|
+
return Math.max(textWidth, interactiveWidth);
|
|
581
|
+
}
|
|
582
|
+
return textWidth;
|
|
583
|
+
}
|
|
584
|
+
areWidthsEqual(prev, next) {
|
|
585
|
+
if (prev.length !== next.length)
|
|
586
|
+
return false;
|
|
587
|
+
return prev.every((v, i) => v === next[i]);
|
|
588
|
+
}
|
|
589
|
+
measureTextWidth(text, style) {
|
|
590
|
+
const fontSize = parseFloat(style.fontSize) || 14;
|
|
591
|
+
const font = style.font || `${style.fontStyle} ${style.fontVariant} ${style.fontWeight} ${style.fontSize} / ${style.lineHeight} ${style.fontFamily}`;
|
|
592
|
+
let contentWidth = 0;
|
|
593
|
+
const isJsdom = typeof navigator !== 'undefined' && /jsdom/i.test(navigator.userAgent);
|
|
594
|
+
const canvas = !isJsdom && typeof document !== 'undefined' ? document.createElement('canvas') : null;
|
|
595
|
+
let ctx = null;
|
|
596
|
+
if (canvas?.getContext) {
|
|
597
|
+
try {
|
|
598
|
+
ctx = canvas.getContext('2d');
|
|
599
|
+
}
|
|
600
|
+
catch {
|
|
601
|
+
ctx = null;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
if (ctx && font) {
|
|
605
|
+
ctx.font = font;
|
|
606
|
+
const metrics = ctx.measureText(text);
|
|
607
|
+
contentWidth = metrics?.width ?? 0;
|
|
608
|
+
}
|
|
609
|
+
if (!contentWidth) {
|
|
610
|
+
contentWidth = text.length * (fontSize * CHAR_WIDTH_FACTOR);
|
|
611
|
+
}
|
|
612
|
+
return contentWidth;
|
|
613
|
+
}
|
|
614
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbSyncColgroupDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
|
|
615
|
+
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 });
|
|
616
|
+
}
|
|
617
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbSyncColgroupDirective, decorators: [{
|
|
618
|
+
type: Directive,
|
|
619
|
+
args: [{
|
|
620
|
+
selector: '[ngbSyncColgroup]',
|
|
621
|
+
standalone: true
|
|
622
|
+
}]
|
|
623
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { syncId: [{
|
|
624
|
+
type: Input,
|
|
625
|
+
args: ['ngbSyncColgroup']
|
|
626
|
+
}], syncRole: [{
|
|
627
|
+
type: Input
|
|
628
|
+
}], onResize: [{
|
|
629
|
+
type: HostListener,
|
|
630
|
+
args: ['window:resize']
|
|
631
|
+
}] } });
|
|
632
|
+
|
|
334
633
|
const MAX_EMAIL_LENGTH = 254;
|
|
335
634
|
const isReasonableEmail = (value) => {
|
|
336
635
|
if (value == null)
|
|
@@ -372,6 +671,40 @@ class Datagrid {
|
|
|
372
671
|
addButtonAriaLabel = 'Add row';
|
|
373
672
|
/** Visible text rendered inside the add-row button. */
|
|
374
673
|
addButtonText = '+ Add';
|
|
674
|
+
/** Shows sticky toggle column and keeps pinned rows at the top of the list. */
|
|
675
|
+
stickyRows = false;
|
|
676
|
+
/** Enables sticky column header when scrolling. */
|
|
677
|
+
stickyHeader = false;
|
|
678
|
+
/** Enables sticky footer when scrolling. */
|
|
679
|
+
stickyFooter = false;
|
|
680
|
+
/** Enables scroll table body container */
|
|
681
|
+
scrollable = true;
|
|
682
|
+
/** Row height used to stack multiple sticky rows without overlap (px). */
|
|
683
|
+
stickyRowHeight = 40;
|
|
684
|
+
/** Header height (px) used to offset sticky rows below the header. */
|
|
685
|
+
stickyHeaderHeight = 40;
|
|
686
|
+
/** Footer height (px) used to offset scrollable area. */
|
|
687
|
+
stickyFooterHeight = 56;
|
|
688
|
+
/** Bootstrap-like table styling options. */
|
|
689
|
+
tableOptions = {};
|
|
690
|
+
/** Selection mode for rows. */
|
|
691
|
+
selectionMode = 'none';
|
|
692
|
+
/** Selection activation: row click, checkbox only, or both. */
|
|
693
|
+
selectionBehavior = 'row';
|
|
694
|
+
/** Keyboard modifier rules for multi-select. */
|
|
695
|
+
selectionKeyMode = 'desktop';
|
|
696
|
+
/** Enable header select-all checkbox for multiple mode. */
|
|
697
|
+
selectAllEnabled = true;
|
|
698
|
+
/** A11y labels for selection controls. */
|
|
699
|
+
selectionA11yLabels = {};
|
|
700
|
+
/** Disable selection for specific rows. */
|
|
701
|
+
selectionDisabledFn;
|
|
702
|
+
/** Highlight items (row/cell). */
|
|
703
|
+
highlightedIndex = [];
|
|
704
|
+
/** Row key for highlighting. */
|
|
705
|
+
highlightRowKey = null;
|
|
706
|
+
/** Column key for highlighting. */
|
|
707
|
+
highlightColKey = null;
|
|
375
708
|
/** Accessible label for the global filter input. */
|
|
376
709
|
globalFilterAriaLabel = 'Search all columns';
|
|
377
710
|
/** Accessible label announced when expanding a row. */
|
|
@@ -402,6 +735,9 @@ class Datagrid {
|
|
|
402
735
|
dataProviderSelection; // used when pages='selection'
|
|
403
736
|
// Grab the directive and its TemplateRef
|
|
404
737
|
exportButtonDir;
|
|
738
|
+
bodyScroller;
|
|
739
|
+
headerScroller;
|
|
740
|
+
colgroupSyncId = `dg-col-${Math.random().toString(36).slice(2, 8)}`;
|
|
405
741
|
exporting = false;
|
|
406
742
|
rowAdd = new EventEmitter();
|
|
407
743
|
// events
|
|
@@ -412,6 +748,7 @@ class Datagrid {
|
|
|
412
748
|
sortChange = new EventEmitter();
|
|
413
749
|
filtersChange = new EventEmitter();
|
|
414
750
|
pageChange = new EventEmitter();
|
|
751
|
+
selectionChange = new EventEmitter();
|
|
415
752
|
rowDetailTpl;
|
|
416
753
|
exporter = inject(NgbExportService); // instead of constructor(private exporter: NgbExportService) {}
|
|
417
754
|
expanded = new Set();
|
|
@@ -423,6 +760,10 @@ class Datagrid {
|
|
|
423
760
|
errorsNew = {};
|
|
424
761
|
// --- sorting (from previous step)
|
|
425
762
|
sort = { active: null, direction: '' };
|
|
763
|
+
stickyRowIds = new Set();
|
|
764
|
+
selectedRowIds = new Set();
|
|
765
|
+
selectionAnchor = null;
|
|
766
|
+
highlightRowMap = new Map();
|
|
426
767
|
// --- filtering
|
|
427
768
|
globalFilter = '';
|
|
428
769
|
filters = {}; // per-column text
|
|
@@ -436,6 +777,7 @@ class Datagrid {
|
|
|
436
777
|
saveAttemptedNew = false;
|
|
437
778
|
addDraftRowId = null;
|
|
438
779
|
defaultEditService = new NgbDatagridDefaultEditService();
|
|
780
|
+
cdr = inject(ChangeDetectorRef);
|
|
439
781
|
norm(v) {
|
|
440
782
|
return (v ?? '').toString().toLowerCase().trim();
|
|
441
783
|
}
|
|
@@ -538,19 +880,22 @@ class Datagrid {
|
|
|
538
880
|
});
|
|
539
881
|
}
|
|
540
882
|
get sorted() {
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
883
|
+
const base = (!this.enableSorting || !this.sort.active || !this.sort.direction)
|
|
884
|
+
? [...this.filtered]
|
|
885
|
+
: (() => {
|
|
886
|
+
const copy = [...this.filtered];
|
|
887
|
+
const { active, direction } = this.sort;
|
|
888
|
+
copy.sort((a, b) => {
|
|
889
|
+
const av = a?.[active];
|
|
890
|
+
const bv = b?.[active];
|
|
891
|
+
const cmp = typeof av === 'string' && typeof bv === 'string'
|
|
892
|
+
? av.localeCompare(bv, undefined, { numeric: true, sensitivity: 'base' })
|
|
893
|
+
: av < bv ? -1 : av > bv ? 1 : 0;
|
|
894
|
+
return direction === 'asc' ? cmp : -cmp;
|
|
895
|
+
});
|
|
896
|
+
return copy;
|
|
897
|
+
})();
|
|
898
|
+
return this.withStickyRowsFirst(base);
|
|
554
899
|
}
|
|
555
900
|
// pagination (filled in next step)
|
|
556
901
|
get paged() {
|
|
@@ -565,14 +910,78 @@ class Datagrid {
|
|
|
565
910
|
}
|
|
566
911
|
get startIndex() { const total = this.sorted.length; return total ? (this.page - 1) * this.pageSize + 1 : 0; }
|
|
567
912
|
get endIndex() { return Math.min(this.page * this.pageSize, this.sorted.length); }
|
|
913
|
+
get shouldEnableScroll() {
|
|
914
|
+
return this.scrollable;
|
|
915
|
+
}
|
|
916
|
+
get isHeaderSticky() {
|
|
917
|
+
return this.stickyHeaderEnabled && this.shouldEnableScroll;
|
|
918
|
+
}
|
|
919
|
+
get isFooterSticky() {
|
|
920
|
+
return this.stickyFooterEnabled && this.shouldEnableScroll;
|
|
921
|
+
}
|
|
568
922
|
get detailColspan() {
|
|
569
923
|
const actionCols = (this.enableEdit || this.enableDelete) ? 1 : 0;
|
|
570
924
|
const caretCol = this.rowDetailTpl ? 1 : 0;
|
|
571
|
-
|
|
925
|
+
const stickyCol = this.stickyRowsEnabled ? 1 : 0;
|
|
926
|
+
const selectionCol = this.isSelectionEnabled() ? 1 : 0;
|
|
927
|
+
return this.columns.length + actionCols + caretCol + stickyCol + selectionCol;
|
|
928
|
+
}
|
|
929
|
+
get tableClassList() {
|
|
930
|
+
const opts = this.tableOptions || {};
|
|
931
|
+
const cls = ['table'];
|
|
932
|
+
if (opts.stripedRows)
|
|
933
|
+
cls.push('table-striped');
|
|
934
|
+
if (opts.stripedColumns)
|
|
935
|
+
cls.push('table-striped-columns');
|
|
936
|
+
if (opts.hoverRows)
|
|
937
|
+
cls.push('table-hover');
|
|
938
|
+
if (opts.bordered)
|
|
939
|
+
cls.push('table-bordered');
|
|
940
|
+
if (opts.borderless)
|
|
941
|
+
cls.push('table-borderless');
|
|
942
|
+
if (opts.small)
|
|
943
|
+
cls.push('table-sm');
|
|
944
|
+
if (opts.groupDividers)
|
|
945
|
+
cls.push('table-group-divider');
|
|
946
|
+
if (opts.align === 'middle')
|
|
947
|
+
cls.push('align-middle');
|
|
948
|
+
if (opts.align === 'bottom')
|
|
949
|
+
cls.push('align-bottom');
|
|
950
|
+
return cls;
|
|
951
|
+
}
|
|
952
|
+
get responsiveWrapperClasses() {
|
|
953
|
+
const r = this.tableOptions?.responsive;
|
|
954
|
+
if (r === false)
|
|
955
|
+
return [];
|
|
956
|
+
if (r === true || r === undefined)
|
|
957
|
+
return ['table-responsive'];
|
|
958
|
+
return [`table-responsive-${r}`];
|
|
959
|
+
}
|
|
960
|
+
updateHighlightCache() {
|
|
961
|
+
this.highlightRowMap.clear();
|
|
962
|
+
(this.highlightedIndex || []).forEach(item => {
|
|
963
|
+
const rowKey = item.row;
|
|
964
|
+
if (!this.highlightRowMap.has(rowKey))
|
|
965
|
+
this.highlightRowMap.set(rowKey, []);
|
|
966
|
+
this.highlightRowMap.get(rowKey)?.push(item);
|
|
967
|
+
});
|
|
572
968
|
}
|
|
573
969
|
headerText(col) {
|
|
574
970
|
return (col.header ?? col.field ?? '').toString();
|
|
575
971
|
}
|
|
972
|
+
headerTitle(col) {
|
|
973
|
+
const t = col?.title;
|
|
974
|
+
return (t ?? this.headerText(col)) ?? '';
|
|
975
|
+
}
|
|
976
|
+
cellTitle(row, col) {
|
|
977
|
+
const def = col?.cellTitle;
|
|
978
|
+
if (typeof def === 'function')
|
|
979
|
+
return def(row) ?? '';
|
|
980
|
+
if (typeof def === 'string')
|
|
981
|
+
return def;
|
|
982
|
+
const val = row?.[col.field];
|
|
983
|
+
return val === undefined || val === null ? '' : String(val);
|
|
984
|
+
}
|
|
576
985
|
columnFilterAriaLabel(col) {
|
|
577
986
|
return `${this.headerText(col)} filter`;
|
|
578
987
|
}
|
|
@@ -599,6 +1008,18 @@ class Datagrid {
|
|
|
599
1008
|
exportAriaLabel(kind) {
|
|
600
1009
|
return kind === 'pdf' ? this.exportPdfAriaLabel : this.exportExcelAriaLabel;
|
|
601
1010
|
}
|
|
1011
|
+
withStickyRowsFirst(rows) {
|
|
1012
|
+
if (!this.stickyRows || this.stickyRowIds.size === 0)
|
|
1013
|
+
return rows;
|
|
1014
|
+
const sticky = [];
|
|
1015
|
+
const rest = [];
|
|
1016
|
+
rows.forEach(r => {
|
|
1017
|
+
const di = this.data.indexOf(r);
|
|
1018
|
+
const id = this.getRowId(di >= 0 ? di : 0, r);
|
|
1019
|
+
(this.stickyRowIds.has(id) ? sticky : rest).push(r);
|
|
1020
|
+
});
|
|
1021
|
+
return [...sticky, ...rest];
|
|
1022
|
+
}
|
|
602
1023
|
// Helpers to map from paged index → original data index
|
|
603
1024
|
// helper used above
|
|
604
1025
|
dataIndexFromPaged(i) {
|
|
@@ -697,6 +1118,8 @@ class Datagrid {
|
|
|
697
1118
|
ngOnChanges(ch) {
|
|
698
1119
|
if (ch['columns'])
|
|
699
1120
|
this.rebuildFilterForm();
|
|
1121
|
+
if (ch['highlightedIndex'])
|
|
1122
|
+
this.updateHighlightCache();
|
|
700
1123
|
}
|
|
701
1124
|
getRowId(rowIndex, row) {
|
|
702
1125
|
return this.trackBy ? this.trackBy(rowIndex, row) : rowIndex;
|
|
@@ -841,6 +1264,32 @@ class Datagrid {
|
|
|
841
1264
|
const rowIndex = di >= 0 ? di : index;
|
|
842
1265
|
return this.trackBy ? this.trackBy(rowIndex, row) : rowIndex;
|
|
843
1266
|
};
|
|
1267
|
+
rowKeyValue(row, rowIndex) {
|
|
1268
|
+
const key = this.highlightRowKey;
|
|
1269
|
+
if (typeof key === 'function')
|
|
1270
|
+
return key(row, rowIndex);
|
|
1271
|
+
if (typeof key === 'string')
|
|
1272
|
+
return row?.[key];
|
|
1273
|
+
return rowIndex;
|
|
1274
|
+
}
|
|
1275
|
+
colKeyValue(column, colIndex) {
|
|
1276
|
+
const key = this.highlightColKey;
|
|
1277
|
+
if (typeof key === 'function')
|
|
1278
|
+
return key(column, colIndex);
|
|
1279
|
+
if (typeof key === 'string')
|
|
1280
|
+
return column?.[key];
|
|
1281
|
+
return colIndex;
|
|
1282
|
+
}
|
|
1283
|
+
isRowHighlighted(row, rowIndex) {
|
|
1284
|
+
const key = this.rowKeyValue(row, rowIndex);
|
|
1285
|
+
return this.highlightRowMap.has(key) && this.highlightRowMap.get(key)?.some(h => h.columnKey === undefined) === true;
|
|
1286
|
+
}
|
|
1287
|
+
isCellHighlighted(row, rowIndex, column, colIndex) {
|
|
1288
|
+
const key = this.rowKeyValue(row, rowIndex);
|
|
1289
|
+
const colKey = this.colKeyValue(column, colIndex);
|
|
1290
|
+
const items = this.highlightRowMap.get(key);
|
|
1291
|
+
return !!items?.some(h => h.columnKey === colKey);
|
|
1292
|
+
}
|
|
844
1293
|
toggleSort(field) {
|
|
845
1294
|
if (!this.enableSorting)
|
|
846
1295
|
return;
|
|
@@ -920,18 +1369,181 @@ class Datagrid {
|
|
|
920
1369
|
const r = this.responsive;
|
|
921
1370
|
return r === true || (!!r && r.enabled === true);
|
|
922
1371
|
}
|
|
923
|
-
|
|
924
|
-
|
|
1372
|
+
isRowSticky(row, pagedIndex) {
|
|
1373
|
+
if (!this.stickyRows)
|
|
1374
|
+
return false;
|
|
1375
|
+
const di = this.data.indexOf(row);
|
|
1376
|
+
const id = this.getRowId(di >= 0 ? di : pagedIndex, row);
|
|
1377
|
+
return this.stickyRowIds.has(id);
|
|
1378
|
+
}
|
|
1379
|
+
toggleStickyRow(pagedIndex) {
|
|
1380
|
+
if (!this.stickyRows)
|
|
1381
|
+
return;
|
|
1382
|
+
const row = this.paged[pagedIndex];
|
|
1383
|
+
if (!row)
|
|
1384
|
+
return;
|
|
1385
|
+
const di = this.data.indexOf(row);
|
|
1386
|
+
const id = this.getRowId(di >= 0 ? di : pagedIndex, row);
|
|
1387
|
+
if (this.stickyRowIds.has(id))
|
|
1388
|
+
this.stickyRowIds.delete(id);
|
|
1389
|
+
else
|
|
1390
|
+
this.stickyRowIds.add(id);
|
|
1391
|
+
}
|
|
1392
|
+
stickyIcon(row, pagedIndex) {
|
|
1393
|
+
return this.isRowSticky(row, pagedIndex) ? 'pin-angle-fill' : 'pin-fill';
|
|
1394
|
+
}
|
|
1395
|
+
stickyTop(row, pagedIndex) {
|
|
1396
|
+
if (!this.isRowSticky(row, pagedIndex))
|
|
1397
|
+
return null;
|
|
1398
|
+
const stickyBefore = this.paged
|
|
1399
|
+
.slice(0, pagedIndex)
|
|
1400
|
+
.filter((r, idx) => this.isRowSticky(r, idx)).length;
|
|
1401
|
+
return stickyBefore * this.stickyRowHeight;
|
|
1402
|
+
}
|
|
1403
|
+
// Selection helpers
|
|
1404
|
+
get stickyRowsEnabled() {
|
|
1405
|
+
return this.tableOptions?.stickyRows ?? this.stickyRows;
|
|
1406
|
+
}
|
|
1407
|
+
get stickyHeaderEnabled() {
|
|
1408
|
+
return this.tableOptions?.stickyHeader ?? this.stickyHeader;
|
|
1409
|
+
}
|
|
1410
|
+
get stickyFooterEnabled() {
|
|
1411
|
+
return this.tableOptions?.stickyFooter ?? this.stickyFooter;
|
|
1412
|
+
}
|
|
1413
|
+
isSelectionEnabled() {
|
|
1414
|
+
return this.selectionMode !== 'none';
|
|
1415
|
+
}
|
|
1416
|
+
isCheckboxOnly() {
|
|
1417
|
+
return this.selectionBehavior === 'checkbox';
|
|
1418
|
+
}
|
|
1419
|
+
isSelectionDisabled(row, pagedIndex) {
|
|
1420
|
+
if (!this.selectionDisabledFn)
|
|
1421
|
+
return false;
|
|
1422
|
+
const di = this.data.indexOf(this.paged[pagedIndex]);
|
|
1423
|
+
return this.selectionDisabledFn(row, di >= 0 ? di : pagedIndex);
|
|
1424
|
+
}
|
|
1425
|
+
isRowSelected(row, pagedIndex) {
|
|
1426
|
+
const di = this.data.indexOf(this.paged[pagedIndex]);
|
|
1427
|
+
const id = this.getRowId(di >= 0 ? di : pagedIndex, row);
|
|
1428
|
+
return this.selectedRowIds.has(id);
|
|
1429
|
+
}
|
|
1430
|
+
toggleSelection(pagedIndex, event) {
|
|
1431
|
+
if (!this.isSelectionEnabled())
|
|
1432
|
+
return;
|
|
1433
|
+
const row = this.paged[pagedIndex];
|
|
1434
|
+
if (!row || this.isSelectionDisabled(row, pagedIndex))
|
|
1435
|
+
return;
|
|
1436
|
+
const di = this.data.indexOf(row);
|
|
1437
|
+
const id = this.getRowId(di >= 0 ? di : pagedIndex, row);
|
|
1438
|
+
const currentlySelected = this.selectedRowIds.has(id);
|
|
1439
|
+
const isMulti = this.selectionMode === 'multiple';
|
|
1440
|
+
const desktop = this.selectionKeyMode === 'desktop';
|
|
1441
|
+
const shift = desktop && !!(event && 'shiftKey' in event && event.shiftKey);
|
|
1442
|
+
const meta = desktop && !!(event && (('metaKey' in event && event.metaKey) || ('ctrlKey' in event && event.ctrlKey)));
|
|
1443
|
+
if (!isMulti) {
|
|
1444
|
+
this.selectedRowIds.clear();
|
|
1445
|
+
this.selectedRowIds.add(id);
|
|
1446
|
+
this.selectionAnchor = pagedIndex;
|
|
1447
|
+
this.emitSelection(row, di, true);
|
|
1448
|
+
return;
|
|
1449
|
+
}
|
|
1450
|
+
if (shift && this.selectionAnchor != null) {
|
|
1451
|
+
const start = Math.min(this.selectionAnchor, pagedIndex);
|
|
1452
|
+
const end = Math.max(this.selectionAnchor, pagedIndex);
|
|
1453
|
+
this.selectedRowIds.clear();
|
|
1454
|
+
for (let i = start; i <= end; i++) {
|
|
1455
|
+
const r = this.paged[i];
|
|
1456
|
+
if (!r || this.isSelectionDisabled(r, i))
|
|
1457
|
+
continue;
|
|
1458
|
+
const rid = this.getRowId(this.data.indexOf(r), r);
|
|
1459
|
+
this.selectedRowIds.add(rid);
|
|
1460
|
+
}
|
|
1461
|
+
this.emitSelection(row, di, true);
|
|
1462
|
+
return;
|
|
1463
|
+
}
|
|
1464
|
+
if (meta || !desktop) {
|
|
1465
|
+
if (currentlySelected)
|
|
1466
|
+
this.selectedRowIds.delete(id);
|
|
1467
|
+
else
|
|
1468
|
+
this.selectedRowIds.add(id);
|
|
1469
|
+
}
|
|
1470
|
+
else {
|
|
1471
|
+
this.selectedRowIds.clear();
|
|
1472
|
+
this.selectedRowIds.add(id);
|
|
1473
|
+
}
|
|
1474
|
+
this.selectionAnchor = pagedIndex;
|
|
1475
|
+
this.emitSelection(row, di, !currentlySelected || (!meta && desktop));
|
|
1476
|
+
}
|
|
1477
|
+
emitSelection(row, dataIndex, selected) {
|
|
1478
|
+
this.selectionChange.emit({
|
|
1479
|
+
selected: this.data.filter((r, idx) => this.selectedRowIds.has(this.getRowId(idx, r))),
|
|
1480
|
+
lastAction: { row, index: dataIndex, selected }
|
|
1481
|
+
});
|
|
1482
|
+
}
|
|
1483
|
+
toggleSelectAllCurrentPage() {
|
|
1484
|
+
if (this.selectionMode !== 'multiple' || !this.selectAllEnabled)
|
|
1485
|
+
return;
|
|
1486
|
+
const allSelectable = this.paged.filter((r, i) => !this.isSelectionDisabled(r, i));
|
|
1487
|
+
const allSelected = allSelectable.every((r, i) => this.isRowSelected(r, i));
|
|
1488
|
+
if (allSelected) {
|
|
1489
|
+
allSelectable.forEach((r, i) => {
|
|
1490
|
+
const rid = this.getRowId(this.data.indexOf(r), r);
|
|
1491
|
+
this.selectedRowIds.delete(rid);
|
|
1492
|
+
});
|
|
1493
|
+
}
|
|
1494
|
+
else {
|
|
1495
|
+
allSelectable.forEach((r, i) => {
|
|
1496
|
+
const rid = this.getRowId(this.data.indexOf(r), r);
|
|
1497
|
+
this.selectedRowIds.add(rid);
|
|
1498
|
+
});
|
|
1499
|
+
}
|
|
1500
|
+
this.selectionChange.emit({
|
|
1501
|
+
selected: this.data.filter((r, idx) => this.selectedRowIds.has(this.getRowId(idx, r))),
|
|
1502
|
+
lastAction: null
|
|
1503
|
+
});
|
|
1504
|
+
}
|
|
1505
|
+
isPageAllSelected() {
|
|
1506
|
+
const selectable = this.paged.filter((r, i) => !this.isSelectionDisabled(r, i));
|
|
1507
|
+
return selectable.length > 0 && selectable.every((r, i) => this.isRowSelected(r, i));
|
|
1508
|
+
}
|
|
1509
|
+
isPageIndeterminate() {
|
|
1510
|
+
const selectable = this.paged.filter((r, i) => !this.isSelectionDisabled(r, i));
|
|
1511
|
+
const selectedCount = selectable.filter((r, i) => this.isRowSelected(r, i)).length;
|
|
1512
|
+
return selectedCount > 0 && selectedCount < selectable.length;
|
|
1513
|
+
}
|
|
1514
|
+
selectAllLabel() {
|
|
1515
|
+
const labels = this.selectionA11yLabels || {};
|
|
1516
|
+
return this.isPageAllSelected()
|
|
1517
|
+
? (labels.unselectAll || 'Unselect all rows')
|
|
1518
|
+
: (labels.selectAll || 'Select all rows');
|
|
1519
|
+
}
|
|
1520
|
+
rowSelectionLabel(index) {
|
|
1521
|
+
const labels = this.selectionA11yLabels || {};
|
|
1522
|
+
const selected = this.isRowSelected(this.paged[index], index);
|
|
1523
|
+
return selected
|
|
1524
|
+
? (labels.unselectRow || `Unselect row ${index + 1}`)
|
|
1525
|
+
: (labels.selectRow || `Select row ${index + 1}`);
|
|
1526
|
+
}
|
|
1527
|
+
onRowSelect(ev, pagedIndex) {
|
|
1528
|
+
if (!this.isSelectionEnabled() || this.isCheckboxOnly())
|
|
1529
|
+
return;
|
|
1530
|
+
const target = ev.target;
|
|
1531
|
+
if (target.closest('input, button, a, select, textarea,label'))
|
|
1532
|
+
return;
|
|
1533
|
+
this.toggleSelection(pagedIndex, ev);
|
|
1534
|
+
}
|
|
1535
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: Datagrid, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1536
|
+
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
1537
|
{ provide: PdfExportAdapter, useClass: JsPdfAdapter },
|
|
926
1538
|
{ 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 });
|
|
1539
|
+
], 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\n class=\"ngb-grid\"\n [attr.data-theme]=\"theme\"\n [class.ngb-responsive]=\"isResponsiveEnabled()\"\n>\n <!-- Export toolbar -->\n <div class=\"d-flex justify-content-end mb-2\" *ngIf=\"exportOptions?.enabled\">\n <ng-container\n *ngIf=\"exportButtonTpl; else defaultExportBtns\"\n [ngTemplateOutlet]=\"exportButtonTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: triggerExport }\"\n >\n </ng-container>\n\n <ng-template #defaultExportBtns>\n <button\n 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 >\n Export to PDF\n </button>\n <button\n 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 >\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\n class=\"table-wrapper\"\n [ngClass]=\"responsiveWrapperClasses\"\n >\n <!-- <div class=\"table-header\"> -->\n <table class=\"grid-table grid-header mb-0\" [ngClass]=\"tableClassList\">\n <caption\n *ngIf=\"tableOptions?.caption\"\n [class.caption-top]=\"(tableOptions?.captionSide ?? 'top') === 'top'\"\n >\n {{\n tableOptions?.caption\n }}\n </caption>\n <colgroup [ngbSyncColgroup]=\"colgroupSyncId\" syncRole=\"header\">\n <col *ngIf=\"isSelectionEnabled()\" style=\"width: 1%\" />\n <col *ngIf=\"rowDetailTpl\" style=\"width: 1%\" data-fixed=\"true\" />\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=\"table-light\">\n <tr>\n <th\n *ngIf=\"isSelectionEnabled()\"\n class=\"text-center\"\n scope=\"col\"\n style=\"width: 1%\"\n >\n <ng-container\n *ngIf=\"selectionMode === 'multiple' && selectAllEnabled\"\n >\n <input\n type=\"checkbox\"\n [checked]=\"isPageAllSelected()\"\n [indeterminate]=\"isPageIndeterminate()\"\n (change)=\"toggleSelectAllCurrentPage()\"\n [attr.aria-label]=\"selectAllLabel()\"\n />\n </ng-container>\n </th>\n <th\n *ngIf=\"rowDetailTpl\"\n style=\"width: 1%\"\n scope=\"col\"\n aria-hidden=\"true\"\n ></th>\n <th\n *ngIf=\"stickyRowsEnabled\"\n style=\"width: 1%\"\n scope=\"col\"\n class=\"text-center\"\n data-title=\"Sticky\"\n ></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.title]=\"headerTitle(col)\"\n [attr.aria-sort]=\"\n enableSorting && col.sortable ? ariaSortFor(col.field) : null\n \"\n >\n <ng-container\n *ngIf=\"enableSorting && col.sortable; else plainHeader\"\n >\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\" class=\"filter-row\" [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\n *ngIf=\"filterTpls[col.field] as ft; else defaultFilter\"\n >\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-scroll]=\"shouldEnableScroll\" #bodyScroller>\n <table\n class=\"grid-table grid-body mb-0\"\n [ngClass]=\"tableClassList\"\n role=\"grid\"\n [attr.aria-readonly]=\"enableEdit || enableAdd ? 'false' : 'true'\"\n >\n <colgroup [ngbSyncColgroup]=\"colgroupSyncId\" syncRole=\"body\">\n <col *ngIf=\"isSelectionEnabled()\" style=\"width: 1%\" />\n <col *ngIf=\"rowDetailTpl\" style=\"width: 1%\" data-fixed=\"true\" />\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]=\"\n (addForm.get(col.field)?.touched || saveAttemptedNew) &&\n addForm.get(col.field)?.invalid\n \"\n >\n <input\n type=\"checkbox\"\n class=\"form-check-input\"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"inputAriaLabel(col)\"\n [attr.aria-invalid]=\"\n (addForm.get(col.field)?.touched || saveAttemptedNew) &&\n addForm.get(col.field)?.invalid\n ? 'true'\n : null\n \"\n [attr.aria-describedby]=\"\n (addForm.get(col.field)?.touched || saveAttemptedNew) &&\n addForm.get(col.field)?.invalid\n ? 'add-error-' + col.field\n : null\n \"\n />\n </div>\n\n <!-- number/email/date/text -->\n <input\n *ngSwitchDefault\n class=\"form-control form-control-sm\"\n [class.is-invalid]=\"\n (addForm.get(col.field)?.touched || saveAttemptedNew) &&\n addForm.get(col.field)?.invalid\n \"\n [attr.type]=\"\n col.type === 'number'\n ? 'number'\n : col.type === 'email'\n ? 'email'\n : col.type === 'date'\n ? 'date'\n : 'text'\n \"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"inputAriaLabel(col)\"\n [attr.aria-invalid]=\"\n (addForm.get(col.field)?.touched || saveAttemptedNew) &&\n addForm.get(col.field)?.invalid\n ? 'true'\n : null\n \"\n [attr.aria-describedby]=\"\n (addForm.get(col.field)?.touched || saveAttemptedNew) &&\n addForm.get(col.field)?.invalid\n ? 'add-error-' + col.field\n : null\n \"\n />\n </ng-container>\n\n <div\n class=\"invalid-feedback d-block\"\n *ngIf=\"\n (addForm.get(col.field)?.touched || saveAttemptedNew) &&\n addForm.get(col.field)?.errors as e\n \"\n [attr.id]=\"'add-error-' + col.field\"\n role=\"alert\"\n >\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\n *ngIf=\"enableEdit || enableDelete\"\n class=\"text-nowrap text-center\"\n >\n <button\n type=\"button\"\n class=\"btn btn-sm btn-success me-1\"\n (click)=\"saveAdd()\"\n [disabled]=\"addForm.invalid\"\n >\n Save\n </button>\n <button\n type=\"button\"\n class=\"btn btn-sm btn-secondary\"\n (click)=\"cancelAdd()\"\n >\n Cancel\n </button>\n </td>\n </tr>\n\n <!-- DATA ROWS + DETAIL ROWS -->\n <ng-container\n *ngFor=\"let row of paged; let i = index; trackBy: trackRow\"\n >\n <!-- DATA ROW (click-to-edit supported) -->\n <tr\n (click)=\"onRowSelect($event, i); onRowClick($event, i)\"\n [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\n type=\"checkbox\"\n [checked]=\"isRowSelected(row, i)\"\n [disabled]=\"\n selectionMode === 'none' ||\n selectionBehavior === 'row' ||\n isSelectionDisabled(row, i)\n \"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleSelection(i, $event)\"\n [attr.aria-label]=\"rowSelectionLabel(i)\"\n />\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]=\"\n isExpanded(i) ? collapseRowAriaLabel : expandRowAriaLabel\n \"\n >\n {{ isExpanded(i) ? \"-\" : \"+\" }}\n </button>\n </td>\n\n <td\n *ngIf=\"stickyRowsEnabled\"\n class=\"text-center align-middle\"\n data-title=\"Sticky\"\n >\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 >\n <ng-container *ngIf=\"stickyIcon(row, i) as icon\">\n <span\n class=\"bi\"\n [ngClass]=\"'bi-' + icon\"\n aria-hidden=\"true\"\n ></span>\n </ng-container>\n </button>\n </td>\n\n <!-- DATA CELLS -->\n <td\n *ngFor=\"let col of columns; let ci = index\"\n [attr.data-title]=\"col.header\"\n [attr.title]=\"cellTitle(row, col)\"\n [class.cell-highlight]=\"isCellHighlighted(row, i, col, ci)\"\n >\n <!-- EDIT MODE -->\n <ng-container\n *ngIf=\"\n editingIndex === i && (col.editable ?? true);\n else readCell\n \"\n >\n <!-- editor template override -->\n <ng-container\n *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,\n col: col,\n form: editForm,\n index: i,\n isNew: false,\n }\"\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\n type=\"checkbox\"\n class=\"form-check-input\"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"inputAriaLabel(col)\"\n [attr.aria-invalid]=\"\n (editForm?.touched || saveAttemptedEdit) &&\n editForm?.get(col.field)?.invalid\n ? 'true'\n : null\n \"\n [attr.aria-describedby]=\"\n (editForm?.touched || saveAttemptedEdit) &&\n editForm?.get(col.field)?.invalid\n ? 'edit-error-' + col.field\n : null\n \"\n />\n </div>\n <select\n *ngSwitchCase=\"'select'\"\n class=\"form-select form-select-sm\"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"inputAriaLabel(col)\"\n >\n <option\n *ngFor=\"let o of col.options ?? []\"\n [ngValue]=\"o.value\"\n >\n {{ o.label }}\n </option>\n </select>\n <input\n *ngSwitchDefault\n class=\"form-control form-control-sm\"\n [attr.type]=\"\n col.type === 'number'\n ? 'number'\n : col.type === 'email'\n ? 'email'\n : col.type === 'date'\n ? 'date'\n : 'text'\n \"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"inputAriaLabel(col)\"\n [attr.aria-invalid]=\"\n (editForm?.touched || saveAttemptedEdit) &&\n editForm?.get(col.field)?.invalid\n ? 'true'\n : null\n \"\n [attr.aria-describedby]=\"\n (editForm?.touched || saveAttemptedEdit) &&\n editForm?.get(col.field)?.invalid\n ? 'edit-error-' + col.field\n : null\n \"\n />\n </ng-container>\n\n <div\n class=\"invalid-feedback d-block\"\n *ngIf=\"\n (editForm?.touched || saveAttemptedEdit) &&\n editForm?.get(col.field)?.errors as e\n \"\n [attr.id]=\"'edit-error-' + col.field\"\n role=\"alert\"\n >\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\n *ngIf=\"cellTpls[col.field] as ct; else defaultCell\"\n [ngTemplateOutlet]=\"ct.template\"\n [ngTemplateOutletContext]=\"{\n $implicit: row[col.field],\n row: row,\n col: col,\n index: i,\n }\"\n >\n </ng-container>\n <ng-template #defaultCell>\n <ng-container [ngSwitch]=\"col.type\">\n <span *ngSwitchCase=\"'boolean'\">{{\n row[col.field] ? \"Yes\" : \"No\"\n }}</span>\n <span *ngSwitchDefault>{{ row[col.field] }}</span>\n </ng-container>\n </ng-template>\n </ng-template>\n </td>\n\n <!-- ACTIONS -->\n <td\n *ngIf=\"enableEdit || enableDelete\"\n class=\"text-nowrap text-center\"\n >\n <ng-container *ngIf=\"editingIndex !== i; else editBtns\">\n <button\n type=\"button\"\n *ngIf=\"enableEdit\"\n class=\"btn btn-sm btn-outline-primary me-1 no-edit-trigger\"\n (click)=\"startEdit(i)\"\n >\n Edit\n </button>\n <button\n type=\"button\"\n *ngIf=\"enableDelete\"\n class=\"btn btn-sm btn-outline-danger no-edit-trigger\"\n (click)=\"deleteRow(i)\"\n >\n Delete\n </button>\n </ng-container>\n <ng-template #editBtns>\n <button\n type=\"button\"\n class=\"btn btn-sm btn-success me-1\"\n (click)=\"saveEdit(i)\"\n [disabled]=\"editForm.invalid\"\n >\n Save\n </button>\n <button\n type=\"button\"\n class=\"btn btn-sm btn-secondary\"\n (click)=\"cancelEdit(i)\"\n >\n Cancel\n </button>\n </ng-template>\n </td>\n </tr>\n\n <!-- DETAIL ROW (spans all columns) -->\n <tr\n *ngIf=\"rowDetailTpl && isExpanded(i)\"\n [attr.id]=\"'dg-row-detail-' + i\"\n >\n <td [attr.colspan]=\"detailColspan\" role=\"region\">\n <ng-container\n [ngTemplateOutlet]=\"rowDetailTpl.template\"\n [ngTemplateOutletContext]=\"{ $implicit: row, index: i }\"\n >\n </ng-container>\n </td>\n </tr>\n </ng-container>\n </tbody>\n </table>\n </div>\n <table class=\"table grid-table grid-foot mb-0\">\n <colgroup>\n <ng-container *ngFor=\"let col of columns\">\n <col [style.width.px]=\"col?.width\" />\n </ng-container>\n </colgroup>\n <tbody>\n <tr>\n <td [attr.colspan]=\"columns.length\" width=\"100%\">\n <div\n *ngIf=\"enablePagination\"\n class=\"d-flex align-items-center justify-content-between mt-2 grid-footer\"\n [class.sticky-footer]=\"isFooterSticky\"\n >\n <!-- left: count -->\n <div class=\"small text-muted\" aria-live=\"polite\">\n {{ startIndex }} - {{ endIndex }} of {{ sorted.length }}\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 >\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\"\n >Rows:</label\n >\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 >\n <option *ngFor=\"let s of pageSizeOptions\" [value]=\"s\">\n {{ s }}\n </option>\n </select>\n </div>\n </div>\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n</div>\n\n<!-- Footer (left = count, center = pagination, right = page size) -->\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{overflow-x:auto;border:1px solid #dee2e6;border-radius:12px;background:#fff}.table-body-scroll{max-height:320px;overflow-y:auto;overflow-x:hidden;border-top:1px solid #e9ecef;border-bottom:1px solid #e9ecef;scrollbar-gutter:stable both-edges;display:inline-block;width:fit-content;vertical-align:top}.grid-head{border-bottom:0}.grid-table{width:100%;min-width:1200px;table-layout:fixed;margin:0;border-collapse:separate;border-spacing:0}.grid-head{position:relative;z-index:5}.grid-head thead tr:first-child th:first-child{border-top-left-radius:12px}.grid-head thead th{background:var(--bs-table-bg, #f8f9fa);border-bottom:1px solid #dee2e6;font-weight:600}.grid-table th,.grid-table td{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;vertical-align:middle;border-bottom:1px solid #e9ecef;padding:.55rem .65rem}.filter-row td{background:#fff;border-bottom:1px solid #dee2e6;padding-top:.45rem;padding-bottom:.45rem}.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
1540
|
}
|
|
929
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.
|
|
1541
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: Datagrid, decorators: [{
|
|
930
1542
|
type: Component,
|
|
931
|
-
args: [{ selector: 'ngb-datagrid', imports: [CommonModule, FormsModule, NgbPaginationComponent, ReactiveFormsModule], providers: [
|
|
1543
|
+
args: [{ selector: 'ngb-datagrid', imports: [CommonModule, FormsModule, NgbPaginationComponent, ReactiveFormsModule, NgbSyncColgroupDirective, NgbGridHighlightDirective], providers: [
|
|
932
1544
|
{ provide: PdfExportAdapter, useClass: JsPdfAdapter },
|
|
933
1545
|
{ 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"] }]
|
|
1546
|
+
], 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\n class=\"ngb-grid\"\n [attr.data-theme]=\"theme\"\n [class.ngb-responsive]=\"isResponsiveEnabled()\"\n>\n <!-- Export toolbar -->\n <div class=\"d-flex justify-content-end mb-2\" *ngIf=\"exportOptions?.enabled\">\n <ng-container\n *ngIf=\"exportButtonTpl; else defaultExportBtns\"\n [ngTemplateOutlet]=\"exportButtonTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: triggerExport }\"\n >\n </ng-container>\n\n <ng-template #defaultExportBtns>\n <button\n 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 >\n Export to PDF\n </button>\n <button\n 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 >\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\n class=\"table-wrapper\"\n [ngClass]=\"responsiveWrapperClasses\"\n >\n <!-- <div class=\"table-header\"> -->\n <table class=\"grid-table grid-header mb-0\" [ngClass]=\"tableClassList\">\n <caption\n *ngIf=\"tableOptions?.caption\"\n [class.caption-top]=\"(tableOptions?.captionSide ?? 'top') === 'top'\"\n >\n {{\n tableOptions?.caption\n }}\n </caption>\n <colgroup [ngbSyncColgroup]=\"colgroupSyncId\" syncRole=\"header\">\n <col *ngIf=\"isSelectionEnabled()\" style=\"width: 1%\" />\n <col *ngIf=\"rowDetailTpl\" style=\"width: 1%\" data-fixed=\"true\" />\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=\"table-light\">\n <tr>\n <th\n *ngIf=\"isSelectionEnabled()\"\n class=\"text-center\"\n scope=\"col\"\n style=\"width: 1%\"\n >\n <ng-container\n *ngIf=\"selectionMode === 'multiple' && selectAllEnabled\"\n >\n <input\n type=\"checkbox\"\n [checked]=\"isPageAllSelected()\"\n [indeterminate]=\"isPageIndeterminate()\"\n (change)=\"toggleSelectAllCurrentPage()\"\n [attr.aria-label]=\"selectAllLabel()\"\n />\n </ng-container>\n </th>\n <th\n *ngIf=\"rowDetailTpl\"\n style=\"width: 1%\"\n scope=\"col\"\n aria-hidden=\"true\"\n ></th>\n <th\n *ngIf=\"stickyRowsEnabled\"\n style=\"width: 1%\"\n scope=\"col\"\n class=\"text-center\"\n data-title=\"Sticky\"\n ></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.title]=\"headerTitle(col)\"\n [attr.aria-sort]=\"\n enableSorting && col.sortable ? ariaSortFor(col.field) : null\n \"\n >\n <ng-container\n *ngIf=\"enableSorting && col.sortable; else plainHeader\"\n >\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\" class=\"filter-row\" [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\n *ngIf=\"filterTpls[col.field] as ft; else defaultFilter\"\n >\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-scroll]=\"shouldEnableScroll\" #bodyScroller>\n <table\n class=\"grid-table grid-body mb-0\"\n [ngClass]=\"tableClassList\"\n role=\"grid\"\n [attr.aria-readonly]=\"enableEdit || enableAdd ? 'false' : 'true'\"\n >\n <colgroup [ngbSyncColgroup]=\"colgroupSyncId\" syncRole=\"body\">\n <col *ngIf=\"isSelectionEnabled()\" style=\"width: 1%\" />\n <col *ngIf=\"rowDetailTpl\" style=\"width: 1%\" data-fixed=\"true\" />\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]=\"\n (addForm.get(col.field)?.touched || saveAttemptedNew) &&\n addForm.get(col.field)?.invalid\n \"\n >\n <input\n type=\"checkbox\"\n class=\"form-check-input\"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"inputAriaLabel(col)\"\n [attr.aria-invalid]=\"\n (addForm.get(col.field)?.touched || saveAttemptedNew) &&\n addForm.get(col.field)?.invalid\n ? 'true'\n : null\n \"\n [attr.aria-describedby]=\"\n (addForm.get(col.field)?.touched || saveAttemptedNew) &&\n addForm.get(col.field)?.invalid\n ? 'add-error-' + col.field\n : null\n \"\n />\n </div>\n\n <!-- number/email/date/text -->\n <input\n *ngSwitchDefault\n class=\"form-control form-control-sm\"\n [class.is-invalid]=\"\n (addForm.get(col.field)?.touched || saveAttemptedNew) &&\n addForm.get(col.field)?.invalid\n \"\n [attr.type]=\"\n col.type === 'number'\n ? 'number'\n : col.type === 'email'\n ? 'email'\n : col.type === 'date'\n ? 'date'\n : 'text'\n \"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"inputAriaLabel(col)\"\n [attr.aria-invalid]=\"\n (addForm.get(col.field)?.touched || saveAttemptedNew) &&\n addForm.get(col.field)?.invalid\n ? 'true'\n : null\n \"\n [attr.aria-describedby]=\"\n (addForm.get(col.field)?.touched || saveAttemptedNew) &&\n addForm.get(col.field)?.invalid\n ? 'add-error-' + col.field\n : null\n \"\n />\n </ng-container>\n\n <div\n class=\"invalid-feedback d-block\"\n *ngIf=\"\n (addForm.get(col.field)?.touched || saveAttemptedNew) &&\n addForm.get(col.field)?.errors as e\n \"\n [attr.id]=\"'add-error-' + col.field\"\n role=\"alert\"\n >\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\n *ngIf=\"enableEdit || enableDelete\"\n class=\"text-nowrap text-center\"\n >\n <button\n type=\"button\"\n class=\"btn btn-sm btn-success me-1\"\n (click)=\"saveAdd()\"\n [disabled]=\"addForm.invalid\"\n >\n Save\n </button>\n <button\n type=\"button\"\n class=\"btn btn-sm btn-secondary\"\n (click)=\"cancelAdd()\"\n >\n Cancel\n </button>\n </td>\n </tr>\n\n <!-- DATA ROWS + DETAIL ROWS -->\n <ng-container\n *ngFor=\"let row of paged; let i = index; trackBy: trackRow\"\n >\n <!-- DATA ROW (click-to-edit supported) -->\n <tr\n (click)=\"onRowSelect($event, i); onRowClick($event, i)\"\n [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\n type=\"checkbox\"\n [checked]=\"isRowSelected(row, i)\"\n [disabled]=\"\n selectionMode === 'none' ||\n selectionBehavior === 'row' ||\n isSelectionDisabled(row, i)\n \"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleSelection(i, $event)\"\n [attr.aria-label]=\"rowSelectionLabel(i)\"\n />\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]=\"\n isExpanded(i) ? collapseRowAriaLabel : expandRowAriaLabel\n \"\n >\n {{ isExpanded(i) ? \"-\" : \"+\" }}\n </button>\n </td>\n\n <td\n *ngIf=\"stickyRowsEnabled\"\n class=\"text-center align-middle\"\n data-title=\"Sticky\"\n >\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 >\n <ng-container *ngIf=\"stickyIcon(row, i) as icon\">\n <span\n class=\"bi\"\n [ngClass]=\"'bi-' + icon\"\n aria-hidden=\"true\"\n ></span>\n </ng-container>\n </button>\n </td>\n\n <!-- DATA CELLS -->\n <td\n *ngFor=\"let col of columns; let ci = index\"\n [attr.data-title]=\"col.header\"\n [attr.title]=\"cellTitle(row, col)\"\n [class.cell-highlight]=\"isCellHighlighted(row, i, col, ci)\"\n >\n <!-- EDIT MODE -->\n <ng-container\n *ngIf=\"\n editingIndex === i && (col.editable ?? true);\n else readCell\n \"\n >\n <!-- editor template override -->\n <ng-container\n *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,\n col: col,\n form: editForm,\n index: i,\n isNew: false,\n }\"\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\n type=\"checkbox\"\n class=\"form-check-input\"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"inputAriaLabel(col)\"\n [attr.aria-invalid]=\"\n (editForm?.touched || saveAttemptedEdit) &&\n editForm?.get(col.field)?.invalid\n ? 'true'\n : null\n \"\n [attr.aria-describedby]=\"\n (editForm?.touched || saveAttemptedEdit) &&\n editForm?.get(col.field)?.invalid\n ? 'edit-error-' + col.field\n : null\n \"\n />\n </div>\n <select\n *ngSwitchCase=\"'select'\"\n class=\"form-select form-select-sm\"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"inputAriaLabel(col)\"\n >\n <option\n *ngFor=\"let o of col.options ?? []\"\n [ngValue]=\"o.value\"\n >\n {{ o.label }}\n </option>\n </select>\n <input\n *ngSwitchDefault\n class=\"form-control form-control-sm\"\n [attr.type]=\"\n col.type === 'number'\n ? 'number'\n : col.type === 'email'\n ? 'email'\n : col.type === 'date'\n ? 'date'\n : 'text'\n \"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"inputAriaLabel(col)\"\n [attr.aria-invalid]=\"\n (editForm?.touched || saveAttemptedEdit) &&\n editForm?.get(col.field)?.invalid\n ? 'true'\n : null\n \"\n [attr.aria-describedby]=\"\n (editForm?.touched || saveAttemptedEdit) &&\n editForm?.get(col.field)?.invalid\n ? 'edit-error-' + col.field\n : null\n \"\n />\n </ng-container>\n\n <div\n class=\"invalid-feedback d-block\"\n *ngIf=\"\n (editForm?.touched || saveAttemptedEdit) &&\n editForm?.get(col.field)?.errors as e\n \"\n [attr.id]=\"'edit-error-' + col.field\"\n role=\"alert\"\n >\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\n *ngIf=\"cellTpls[col.field] as ct; else defaultCell\"\n [ngTemplateOutlet]=\"ct.template\"\n [ngTemplateOutletContext]=\"{\n $implicit: row[col.field],\n row: row,\n col: col,\n index: i,\n }\"\n >\n </ng-container>\n <ng-template #defaultCell>\n <ng-container [ngSwitch]=\"col.type\">\n <span *ngSwitchCase=\"'boolean'\">{{\n row[col.field] ? \"Yes\" : \"No\"\n }}</span>\n <span *ngSwitchDefault>{{ row[col.field] }}</span>\n </ng-container>\n </ng-template>\n </ng-template>\n </td>\n\n <!-- ACTIONS -->\n <td\n *ngIf=\"enableEdit || enableDelete\"\n class=\"text-nowrap text-center\"\n >\n <ng-container *ngIf=\"editingIndex !== i; else editBtns\">\n <button\n type=\"button\"\n *ngIf=\"enableEdit\"\n class=\"btn btn-sm btn-outline-primary me-1 no-edit-trigger\"\n (click)=\"startEdit(i)\"\n >\n Edit\n </button>\n <button\n type=\"button\"\n *ngIf=\"enableDelete\"\n class=\"btn btn-sm btn-outline-danger no-edit-trigger\"\n (click)=\"deleteRow(i)\"\n >\n Delete\n </button>\n </ng-container>\n <ng-template #editBtns>\n <button\n type=\"button\"\n class=\"btn btn-sm btn-success me-1\"\n (click)=\"saveEdit(i)\"\n [disabled]=\"editForm.invalid\"\n >\n Save\n </button>\n <button\n type=\"button\"\n class=\"btn btn-sm btn-secondary\"\n (click)=\"cancelEdit(i)\"\n >\n Cancel\n </button>\n </ng-template>\n </td>\n </tr>\n\n <!-- DETAIL ROW (spans all columns) -->\n <tr\n *ngIf=\"rowDetailTpl && isExpanded(i)\"\n [attr.id]=\"'dg-row-detail-' + i\"\n >\n <td [attr.colspan]=\"detailColspan\" role=\"region\">\n <ng-container\n [ngTemplateOutlet]=\"rowDetailTpl.template\"\n [ngTemplateOutletContext]=\"{ $implicit: row, index: i }\"\n >\n </ng-container>\n </td>\n </tr>\n </ng-container>\n </tbody>\n </table>\n </div>\n <table class=\"table grid-table grid-foot mb-0\">\n <colgroup>\n <ng-container *ngFor=\"let col of columns\">\n <col [style.width.px]=\"col?.width\" />\n </ng-container>\n </colgroup>\n <tbody>\n <tr>\n <td [attr.colspan]=\"columns.length\" width=\"100%\">\n <div\n *ngIf=\"enablePagination\"\n class=\"d-flex align-items-center justify-content-between mt-2 grid-footer\"\n [class.sticky-footer]=\"isFooterSticky\"\n >\n <!-- left: count -->\n <div class=\"small text-muted\" aria-live=\"polite\">\n {{ startIndex }} - {{ endIndex }} of {{ sorted.length }}\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 >\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\"\n >Rows:</label\n >\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 >\n <option *ngFor=\"let s of pageSizeOptions\" [value]=\"s\">\n {{ s }}\n </option>\n </select>\n </div>\n </div>\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n</div>\n\n<!-- Footer (left = count, center = pagination, right = page size) -->\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{overflow-x:auto;border:1px solid #dee2e6;border-radius:12px;background:#fff}.table-body-scroll{max-height:320px;overflow-y:auto;overflow-x:hidden;border-top:1px solid #e9ecef;border-bottom:1px solid #e9ecef;scrollbar-gutter:stable both-edges;display:inline-block;width:fit-content;vertical-align:top}.grid-head{border-bottom:0}.grid-table{width:100%;min-width:1200px;table-layout:fixed;margin:0;border-collapse:separate;border-spacing:0}.grid-head{position:relative;z-index:5}.grid-head thead tr:first-child th:first-child{border-top-left-radius:12px}.grid-head thead th{background:var(--bs-table-bg, #f8f9fa);border-bottom:1px solid #dee2e6;font-weight:600}.grid-table th,.grid-table td{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;vertical-align:middle;border-bottom:1px solid #e9ecef;padding:.55rem .65rem}.filter-row td{background:#fff;border-bottom:1px solid #dee2e6;padding-top:.45rem;padding-bottom:.45rem}.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
1547
|
}], propDecorators: { columns: [{
|
|
936
1548
|
type: Input
|
|
937
1549
|
}], data: [{
|
|
@@ -956,6 +1568,40 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
|
|
|
956
1568
|
type: Input
|
|
957
1569
|
}], addButtonText: [{
|
|
958
1570
|
type: Input
|
|
1571
|
+
}], stickyRows: [{
|
|
1572
|
+
type: Input
|
|
1573
|
+
}], stickyHeader: [{
|
|
1574
|
+
type: Input
|
|
1575
|
+
}], stickyFooter: [{
|
|
1576
|
+
type: Input
|
|
1577
|
+
}], scrollable: [{
|
|
1578
|
+
type: Input
|
|
1579
|
+
}], stickyRowHeight: [{
|
|
1580
|
+
type: Input
|
|
1581
|
+
}], stickyHeaderHeight: [{
|
|
1582
|
+
type: Input
|
|
1583
|
+
}], stickyFooterHeight: [{
|
|
1584
|
+
type: Input
|
|
1585
|
+
}], tableOptions: [{
|
|
1586
|
+
type: Input
|
|
1587
|
+
}], selectionMode: [{
|
|
1588
|
+
type: Input
|
|
1589
|
+
}], selectionBehavior: [{
|
|
1590
|
+
type: Input
|
|
1591
|
+
}], selectionKeyMode: [{
|
|
1592
|
+
type: Input
|
|
1593
|
+
}], selectAllEnabled: [{
|
|
1594
|
+
type: Input
|
|
1595
|
+
}], selectionA11yLabels: [{
|
|
1596
|
+
type: Input
|
|
1597
|
+
}], selectionDisabledFn: [{
|
|
1598
|
+
type: Input
|
|
1599
|
+
}], highlightedIndex: [{
|
|
1600
|
+
type: Input
|
|
1601
|
+
}], highlightRowKey: [{
|
|
1602
|
+
type: Input
|
|
1603
|
+
}], highlightColKey: [{
|
|
1604
|
+
type: Input
|
|
959
1605
|
}], globalFilterAriaLabel: [{
|
|
960
1606
|
type: Input
|
|
961
1607
|
}], expandRowAriaLabel: [{
|
|
@@ -991,6 +1637,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
|
|
|
991
1637
|
}], exportButtonDir: [{
|
|
992
1638
|
type: ContentChild,
|
|
993
1639
|
args: [ExportButtonDirective]
|
|
1640
|
+
}], bodyScroller: [{
|
|
1641
|
+
type: ViewChild,
|
|
1642
|
+
args: ['bodyScroller']
|
|
1643
|
+
}], headerScroller: [{
|
|
1644
|
+
type: ViewChild,
|
|
1645
|
+
args: ['headerScroller']
|
|
994
1646
|
}], rowAdd: [{
|
|
995
1647
|
type: Output
|
|
996
1648
|
}], rowEdit: [{
|
|
@@ -1007,6 +1659,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
|
|
|
1007
1659
|
type: Output
|
|
1008
1660
|
}], pageChange: [{
|
|
1009
1661
|
type: Output
|
|
1662
|
+
}], selectionChange: [{
|
|
1663
|
+
type: Output
|
|
1010
1664
|
}], rowDetailTpl: [{
|
|
1011
1665
|
type: ContentChild,
|
|
1012
1666
|
args: [NgbRowDetailTemplate]
|
|
@@ -1043,10 +1697,10 @@ class NgbLiveAnnouncer {
|
|
|
1043
1697
|
}
|
|
1044
1698
|
this.node.textContent = message;
|
|
1045
1699
|
}
|
|
1046
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.
|
|
1047
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.
|
|
1700
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbLiveAnnouncer, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1701
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbLiveAnnouncer, providedIn: 'root' });
|
|
1048
1702
|
}
|
|
1049
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.
|
|
1703
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbLiveAnnouncer, decorators: [{
|
|
1050
1704
|
type: Injectable,
|
|
1051
1705
|
args: [{ providedIn: 'root' }]
|
|
1052
1706
|
}] });
|
|
@@ -1099,10 +1753,10 @@ class NgbDndState {
|
|
|
1099
1753
|
if (this.store.size === 0)
|
|
1100
1754
|
this.active.set(false);
|
|
1101
1755
|
}
|
|
1102
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.
|
|
1103
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.
|
|
1756
|
+
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 });
|
|
1757
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbDndState, providedIn: 'root' });
|
|
1104
1758
|
}
|
|
1105
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.
|
|
1759
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbDndState, decorators: [{
|
|
1106
1760
|
type: Injectable,
|
|
1107
1761
|
args: [{ providedIn: 'root' }]
|
|
1108
1762
|
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
@@ -1416,10 +2070,10 @@ class NgbDndListDirective {
|
|
|
1416
2070
|
});
|
|
1417
2071
|
this.state.announce?.(this.state.i18n.dropped());
|
|
1418
2072
|
}
|
|
1419
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.
|
|
1420
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.
|
|
2073
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbDndListDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2074
|
+
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
2075
|
}
|
|
1422
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.
|
|
2076
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbDndListDirective, decorators: [{
|
|
1423
2077
|
type: Directive,
|
|
1424
2078
|
args: [{
|
|
1425
2079
|
selector: '[ngbDndList]',
|
|
@@ -1568,10 +2222,10 @@ class NgbDndItemDirective {
|
|
|
1568
2222
|
this.onDragEnd();
|
|
1569
2223
|
} // cancel
|
|
1570
2224
|
}
|
|
1571
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.
|
|
1572
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.
|
|
2225
|
+
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 });
|
|
2226
|
+
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
2227
|
}
|
|
1574
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.
|
|
2228
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbDndItemDirective, decorators: [{
|
|
1575
2229
|
type: Directive,
|
|
1576
2230
|
args: [{
|
|
1577
2231
|
selector: '[ngbDndItem]',
|
|
@@ -1624,10 +2278,10 @@ class NgbStepLabelDirective {
|
|
|
1624
2278
|
constructor(template) {
|
|
1625
2279
|
this.template = template;
|
|
1626
2280
|
}
|
|
1627
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.
|
|
1628
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.
|
|
2281
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbStepLabelDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
|
|
2282
|
+
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
2283
|
}
|
|
1630
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.
|
|
2284
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbStepLabelDirective, decorators: [{
|
|
1631
2285
|
type: Directive,
|
|
1632
2286
|
args: [{
|
|
1633
2287
|
selector: '[ngbStepLabel]',
|
|
@@ -1822,10 +2476,10 @@ class NgbStepperComponent {
|
|
|
1822
2476
|
step: this.steps[nextIndex],
|
|
1823
2477
|
});
|
|
1824
2478
|
}
|
|
1825
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.
|
|
1826
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.
|
|
2479
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbStepperComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2480
|
+
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
2481
|
}
|
|
1828
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.
|
|
2482
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbStepperComponent, decorators: [{
|
|
1829
2483
|
type: Component,
|
|
1830
2484
|
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
2485
|
}], propDecorators: { steps: [{
|
|
@@ -1894,14 +2548,14 @@ class NgbSplitterPaneComponent {
|
|
|
1894
2548
|
collapsed = false;
|
|
1895
2549
|
collapsedChange = new EventEmitter();
|
|
1896
2550
|
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.
|
|
2551
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbSplitterPaneComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2552
|
+
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
2553
|
<div [style.overflow]="scrollable ? 'auto' : 'hidden'" style="height: 100%; width: 100%;">
|
|
1900
2554
|
<ng-content></ng-content>
|
|
1901
2555
|
</div>
|
|
1902
2556
|
</ng-template>`, isInline: true, styles: [":host{display:block;position:relative}\n"] });
|
|
1903
2557
|
}
|
|
1904
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.
|
|
2558
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbSplitterPaneComponent, decorators: [{
|
|
1905
2559
|
type: Component,
|
|
1906
2560
|
args: [{ selector: 'ngb-splitter-pane', standalone: true, template: `<ng-template #content>
|
|
1907
2561
|
<div [style.overflow]="scrollable ? 'auto' : 'hidden'" style="height: 100%; width: 100%;">
|
|
@@ -2133,8 +2787,8 @@ class NgbSplitterComponent {
|
|
|
2133
2787
|
nextPercent = Math.max(0, Math.min(100, nextPercent));
|
|
2134
2788
|
targetPane.size = `${nextPercent}%`;
|
|
2135
2789
|
}
|
|
2136
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.
|
|
2137
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.
|
|
2790
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbSplitterComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
2791
|
+
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
2792
|
<div class="splitter-container" [class.vertical]="orientation === 'vertical'"
|
|
2139
2793
|
[style.min-height]="orientation === 'vertical' ? verticalMinHeight : null"
|
|
2140
2794
|
[style.height]="orientation === 'vertical' ? verticalMinHeight : null">
|
|
@@ -2178,7 +2832,7 @@ class NgbSplitterComponent {
|
|
|
2178
2832
|
</div>
|
|
2179
2833
|
`, 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
2834
|
}
|
|
2181
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.
|
|
2835
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbSplitterComponent, decorators: [{
|
|
2182
2836
|
type: Component,
|
|
2183
2837
|
args: [{ selector: 'ngb-splitter', standalone: true, imports: [CommonModule, NgbSplitterPaneComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
2184
2838
|
<div class="splitter-container" [class.vertical]="orientation === 'vertical'"
|
|
@@ -2255,8 +2909,8 @@ class NgbChipsComponent {
|
|
|
2255
2909
|
removeLabel;
|
|
2256
2910
|
remove = new EventEmitter();
|
|
2257
2911
|
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.
|
|
2912
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbChipsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2913
|
+
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
2914
|
<div class="ngb-chips" [attr.aria-label]="ariaLabel">
|
|
2261
2915
|
<span
|
|
2262
2916
|
*ngFor="let item of items; trackBy: trackById"
|
|
@@ -2278,7 +2932,7 @@ class NgbChipsComponent {
|
|
|
2278
2932
|
</div>
|
|
2279
2933
|
`, 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
2934
|
}
|
|
2281
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.
|
|
2935
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbChipsComponent, decorators: [{
|
|
2282
2936
|
type: Component,
|
|
2283
2937
|
args: [{ selector: 'ngb-chips', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
2284
2938
|
<div class="ngb-chips" [attr.aria-label]="ariaLabel">
|
|
@@ -3013,8 +3667,8 @@ class NgbTypeaheadComponent {
|
|
|
3013
3667
|
return match;
|
|
3014
3668
|
return { id: `${value}`, label: `${value}`, value };
|
|
3015
3669
|
}
|
|
3016
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.
|
|
3017
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.
|
|
3670
|
+
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 });
|
|
3671
|
+
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
3672
|
{
|
|
3019
3673
|
provide: NG_VALUE_ACCESSOR,
|
|
3020
3674
|
useExisting: forwardRef(() => NgbTypeaheadComponent),
|
|
@@ -3160,7 +3814,7 @@ class NgbTypeaheadComponent {
|
|
|
3160
3814
|
</div>
|
|
3161
3815
|
`, 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
3816
|
}
|
|
3163
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.
|
|
3817
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbTypeaheadComponent, decorators: [{
|
|
3164
3818
|
type: Component,
|
|
3165
3819
|
args: [{ selector: 'ngb-typeahead', standalone: true, imports: [CommonModule, NgbChipsComponent], providers: [
|
|
3166
3820
|
{
|
|
@@ -3483,8 +4137,8 @@ class NgbTreeComponent {
|
|
|
3483
4137
|
}
|
|
3484
4138
|
return acc;
|
|
3485
4139
|
}
|
|
3486
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.
|
|
3487
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.
|
|
4140
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbTreeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4141
|
+
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
4142
|
<div class="d-flex gap-2 mb-2">
|
|
3489
4143
|
<button type="button" class="btn btn-sm btn-outline-secondary" (click)="expandAllNodes()" [attr.aria-label]="i18n?.expandAll || 'Expand all'">
|
|
3490
4144
|
{{ i18n?.expandAll || 'Expand all' }}
|
|
@@ -3550,7 +4204,7 @@ class NgbTreeComponent {
|
|
|
3550
4204
|
</ng-template>
|
|
3551
4205
|
`, 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
4206
|
}
|
|
3553
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.
|
|
4207
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: NgbTreeComponent, decorators: [{
|
|
3554
4208
|
type: Component,
|
|
3555
4209
|
args: [{
|
|
3556
4210
|
selector: 'ngb-tree',
|