@kuzntsv/uikit 0.21.37 → 1.0.1

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.
@@ -0,0 +1,1810 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, output, effect, Component, viewChild, HostListener, inject, Injectable, Directive, signal, Pipe, ChangeDetectorRef, ChangeDetectionStrategy, linkedSignal, NgZone, ElementRef } from '@angular/core';
3
+ import { Router, RouterLink, ActivatedRoute } from '@angular/router';
4
+ import { AuthService, RoleService, NotificationService, UIKIT_NOTIFICATION_TOKEN } from '@kuzntsv/uikit';
5
+ import * as i1 from '@angular/forms';
6
+ import { FormGroup, FormControl, Validators, FormsModule, ReactiveFormsModule, NgControl } from '@angular/forms';
7
+ import { MatButton, MatIconButton, MatAnchor } from '@angular/material/button';
8
+ import { MatCard, MatCardHeader, MatCardTitle, MatCardContent } from '@angular/material/card';
9
+ import { MatFormField, MatLabel, MatError, MatSuffix, MatHint } from '@angular/material/form-field';
10
+ import { MatIcon } from '@angular/material/icon';
11
+ import { MatInput } from '@angular/material/input';
12
+ import { HttpClient, HttpParams } from '@angular/common/http';
13
+ import { Overlay } from '@angular/cdk/overlay';
14
+ import { ComponentPortal } from '@angular/cdk/portal';
15
+ import { ENTER, COMMA } from '@angular/cdk/keycodes';
16
+ import { AsyncPipe } from '@angular/common';
17
+ import * as i2 from '@angular/material/autocomplete';
18
+ import { MatAutocompleteModule, MatOption } from '@angular/material/autocomplete';
19
+ import * as i3 from '@angular/material/chips';
20
+ import { MatChipsModule } from '@angular/material/chips';
21
+ import { startWith, Subscription, Subject, tap, switchMap, map as map$1, forkJoin, ReplaySubject } from 'rxjs';
22
+ import { map, debounceTime, distinctUntilChanged, startWith as startWith$1 } from 'rxjs/operators';
23
+ import { MAT_DATE_LOCALE, MAT_DATE_FORMATS, MatOption as MatOption$1, MatOptgroup } from '@angular/material/core';
24
+ import { MatDateRangeInput, MatStartDate, MatEndDate, MatDatepickerToggle, MatDateRangePicker } from '@angular/material/datepicker';
25
+ import 'moment/locale/ru';
26
+ import moment from 'moment';
27
+ import { MAT_DIALOG_DATA, MatDialogRef, MatDialogTitle, MatDialogContent, MatDialogActions, MatDialogClose, MatDialog, MatDialogConfig } from '@angular/material/dialog';
28
+ import * as i1$1 from '@angular/material/tooltip';
29
+ import { MatTooltip, MatTooltipModule } from '@angular/material/tooltip';
30
+ import { MatDivider } from '@angular/material/divider';
31
+ import { MatMenu, MatMenuTrigger, MatMenuItem, MatMenuContent } from '@angular/material/menu';
32
+ import { MatToolbar } from '@angular/material/toolbar';
33
+ import { DomSanitizer } from '@angular/platform-browser';
34
+ import { MatProgressSpinner } from '@angular/material/progress-spinner';
35
+ import * as i3$1 from '@angular/cdk/scrolling';
36
+ import { ScrollingModule } from '@angular/cdk/scrolling';
37
+ import { MatSelect, MatFormField as MatFormField$1, MatLabel as MatLabel$1 } from '@angular/material/select';
38
+ import { SelectionModel } from '@angular/cdk/collections';
39
+ import { MatCheckbox } from '@angular/material/checkbox';
40
+ import { MatPaginator } from '@angular/material/paginator';
41
+ import { MatSort, MatSortHeader } from '@angular/material/sort';
42
+ import { MatTableDataSource, MatTable, MatColumnDef, MatHeaderCellDef, MatHeaderCell, MatCellDef, MatCell, MatNoDataRow, MatHeaderRowDef, MatHeaderRow, MatRowDef, MatRow, MatFooterRowDef, MatFooterRow, MatFooterCellDef, MatFooterCell, MatTableModule } from '@angular/material/table';
43
+
44
+ class LoginFormComponent {
45
+ pending = input(false, ...(ngDevMode ? [{ debugName: "pending" }] : []));
46
+ errorMessage = input('', ...(ngDevMode ? [{ debugName: "errorMessage" }] : []));
47
+ submitted = output();
48
+ hide = true;
49
+ form = new FormGroup({
50
+ username: new FormControl('', [Validators.required]),
51
+ password: new FormControl('', [Validators.required]),
52
+ });
53
+ constructor() {
54
+ effect(() => {
55
+ if (this.pending()) {
56
+ this.form.disable();
57
+ }
58
+ else {
59
+ this.form.enable();
60
+ }
61
+ });
62
+ }
63
+ submit() {
64
+ if (this.form.valid) {
65
+ this.submitted.emit(this.form.value);
66
+ }
67
+ }
68
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: LoginFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
69
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: LoginFormComponent, isStandalone: true, selector: "ngx-uik-login-form", inputs: { pending: { classPropertyName: "pending", publicName: "pending", isSignal: true, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { submitted: "submitted" }, ngImport: i0, template: "<mat-card appearance=\"outlined\">\r\n <mat-card-header>\r\n <mat-card-title>\r\n \u0410\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u044F\r\n </mat-card-title>\r\n </mat-card-header>\r\n <mat-card-content>\r\n <form [formGroup]=\"form\" (ngSubmit)=\"submit()\">\r\n <p>\r\n <mat-form-field>\r\n <mat-label>\u0418\u043C\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F</mat-label>\r\n <input type=\"text\" pattern=\"[A-Za-z]{1,}.[A-Za-z]{1,}.[A-Za-z]*\"\r\n matInput\r\n autocomplete=\"on\"\r\n name=\"login-form-username\"\r\n placeholder=\"\u0418\u043C\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F\"\r\n formControlName=\"username\">\r\n @if (form.controls['username'].hasError('pattern')) {\r\n <mat-error>\r\n \u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439\u0442\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u043C\u044B\u0439 \u0444\u043E\u0440\u043C\u0430\u0442 (\u041F\u0440\u0438\u043C\u0435\u0440: a.p.petrov)\r\n </mat-error>\r\n }\r\n @if (form.controls['username'].hasError('required')) {\r\n <mat-error>\r\n \u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u0437\u0430\u043F\u043E\u043B\u043D\u0438\u0442\u0435 \u044D\u0442\u043E \u043F\u043E\u043B\u0435\r\n </mat-error>\r\n }\r\n </mat-form-field>\r\n </p>\r\n\r\n <p>\r\n <mat-form-field>\r\n <mat-label>\u041F\u0430\u0440\u043E\u043B\u044C</mat-label>\r\n <input [type]=\"hide ? 'password' : 'text'\" matInput placeholder=\"\u041F\u0430\u0440\u043E\u043B\u044C\" formControlName=\"password\">\r\n <mat-icon class=\"watcher\" matSuffix (mousedown)=\"hide=false\" (mouseup)=\"hide=true\"\r\n >{{ hide ? 'visibility_off' : 'visibility'}}</mat-icon>\r\n @if (form.controls['password'].hasError('required')) {\r\n <mat-error>\r\n \u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u0437\u0430\u043F\u043E\u043B\u043D\u0438\u0442\u0435 \u044D\u0442\u043E \u043F\u043E\u043B\u0435\r\n </mat-error>\r\n }\r\n </mat-form-field>\r\n </p>\r\n\r\n @if (errorMessage()) {\r\n <p class=\"loginError\">\r\n {{ errorMessage() }}\r\n </p>\r\n }\r\n\r\n <p class=\"loginButtons\">\r\n <button type=\"submit\" mat-button mat-stroked-button color=\"primary\" [disabled]=\"pending()\">\u0412\u043E\u0439\u0442\u0438</button>\r\n </p>\r\n\r\n </form>\r\n </mat-card-content>\r\n </mat-card>\r\n", styles: [":host{display:flex;justify-content:center;margin:32px 0}.mat-mdc-form-field{width:100%;min-width:300px}mat-card-header{justify-content:center}mat-card-content{font-size:16px}.loginError{padding:16px;width:300px;color:#fff;background-color:red}.loginButtons{display:flex;flex-direction:row;justify-content:flex-end}.watcher{cursor:default}\n"], dependencies: [{ kind: "component", type: MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "component", type: MatCardHeader, selector: "mat-card-header" }, { kind: "directive", type: MatCardTitle, selector: "mat-card-title, [mat-card-title], [matCardTitle]" }, { kind: "directive", type: MatCardContent, selector: "mat-card-content" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.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: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: MatLabel, selector: "mat-label" }, { kind: "directive", type: MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "directive", type: MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "component", type: MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }] });
70
+ }
71
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: LoginFormComponent, decorators: [{
72
+ type: Component,
73
+ args: [{ selector: 'ngx-uik-login-form', imports: [MatCard, MatCardHeader, MatCardTitle, MatCardContent, FormsModule, ReactiveFormsModule, MatFormField,
74
+ MatLabel, MatInput, MatError, MatIcon, MatSuffix, MatButton], template: "<mat-card appearance=\"outlined\">\r\n <mat-card-header>\r\n <mat-card-title>\r\n \u0410\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u044F\r\n </mat-card-title>\r\n </mat-card-header>\r\n <mat-card-content>\r\n <form [formGroup]=\"form\" (ngSubmit)=\"submit()\">\r\n <p>\r\n <mat-form-field>\r\n <mat-label>\u0418\u043C\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F</mat-label>\r\n <input type=\"text\" pattern=\"[A-Za-z]{1,}.[A-Za-z]{1,}.[A-Za-z]*\"\r\n matInput\r\n autocomplete=\"on\"\r\n name=\"login-form-username\"\r\n placeholder=\"\u0418\u043C\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F\"\r\n formControlName=\"username\">\r\n @if (form.controls['username'].hasError('pattern')) {\r\n <mat-error>\r\n \u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439\u0442\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u043C\u044B\u0439 \u0444\u043E\u0440\u043C\u0430\u0442 (\u041F\u0440\u0438\u043C\u0435\u0440: a.p.petrov)\r\n </mat-error>\r\n }\r\n @if (form.controls['username'].hasError('required')) {\r\n <mat-error>\r\n \u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u0437\u0430\u043F\u043E\u043B\u043D\u0438\u0442\u0435 \u044D\u0442\u043E \u043F\u043E\u043B\u0435\r\n </mat-error>\r\n }\r\n </mat-form-field>\r\n </p>\r\n\r\n <p>\r\n <mat-form-field>\r\n <mat-label>\u041F\u0430\u0440\u043E\u043B\u044C</mat-label>\r\n <input [type]=\"hide ? 'password' : 'text'\" matInput placeholder=\"\u041F\u0430\u0440\u043E\u043B\u044C\" formControlName=\"password\">\r\n <mat-icon class=\"watcher\" matSuffix (mousedown)=\"hide=false\" (mouseup)=\"hide=true\"\r\n >{{ hide ? 'visibility_off' : 'visibility'}}</mat-icon>\r\n @if (form.controls['password'].hasError('required')) {\r\n <mat-error>\r\n \u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u0437\u0430\u043F\u043E\u043B\u043D\u0438\u0442\u0435 \u044D\u0442\u043E \u043F\u043E\u043B\u0435\r\n </mat-error>\r\n }\r\n </mat-form-field>\r\n </p>\r\n\r\n @if (errorMessage()) {\r\n <p class=\"loginError\">\r\n {{ errorMessage() }}\r\n </p>\r\n }\r\n\r\n <p class=\"loginButtons\">\r\n <button type=\"submit\" mat-button mat-stroked-button color=\"primary\" [disabled]=\"pending()\">\u0412\u043E\u0439\u0442\u0438</button>\r\n </p>\r\n\r\n </form>\r\n </mat-card-content>\r\n </mat-card>\r\n", styles: [":host{display:flex;justify-content:center;margin:32px 0}.mat-mdc-form-field{width:100%;min-width:300px}mat-card-header{justify-content:center}mat-card-content{font-size:16px}.loginError{padding:16px;width:300px;color:#fff;background-color:red}.loginButtons{display:flex;flex-direction:row;justify-content:flex-end}.watcher{cursor:default}\n"] }]
75
+ }], ctorParameters: () => [], propDecorators: { pending: [{ type: i0.Input, args: [{ isSignal: true, alias: "pending", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], submitted: [{ type: i0.Output, args: ["submitted"] }] } });
76
+
77
+ class PermitFormComponent {
78
+ hidy = viewChild('hidy', ...(ngDevMode ? [{ debugName: "hidy" }] : []));
79
+ submitted = output();
80
+ mouseHandling(event) {
81
+ this.hidy()?.nativeElement.focus();
82
+ }
83
+ ngOnInit() {
84
+ // Обнуляем значение Input
85
+ const hidy = this.hidy();
86
+ if (hidy) {
87
+ hidy.nativeElement.value = null;
88
+ hidy.nativeElement.focus();
89
+ }
90
+ }
91
+ /**
92
+ * Поле ввода
93
+ *
94
+ * @param событие нажатия на клавишу
95
+ */
96
+ onKeydown(event) {
97
+ if (event.key === 'Enter') {
98
+ const permit = this.hidy()?.nativeElement.value;
99
+ if (permit) {
100
+ this.submitted.emit(permit);
101
+ }
102
+ }
103
+ }
104
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: PermitFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
105
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.1.0", type: PermitFormComponent, isStandalone: true, selector: "ngx-uik-permit-form", outputs: { submitted: "submitted" }, host: { listeners: { "document:mouseup": "mouseHandling($event)" } }, viewQueries: [{ propertyName: "hidy", first: true, predicate: ["hidy"], descendants: true, isSignal: true }], ngImport: i0, template: "<mat-card appearance=\"outlined\">\r\n <mat-card-header>\r\n <mat-card-title>\r\n \u041F\u0440\u0438\u043B\u043E\u0436\u0438\u0442\u0435 \u043F\u0440\u043E\u043F\u0443\u0441\u043A\r\n </mat-card-title>\r\n </mat-card-header>\r\n <mat-card-content>\r\n <div class=\"permit\"></div>\r\n </mat-card-content>\r\n</mat-card>\r\n<input #hidy class=\"hidy\" type=\"text\" (keydown)=\"onKeydown($event)\"/>", styles: [":host{display:flex;justify-content:center;margin:32px 0}.mat-mdc-form-field{width:100%;min-width:300px}mat-card-title,mat-card-content{display:flex;justify-content:center}mat-card-content{font-size:16px}div.permit{border:none;width:300px;background-size:300px;height:180px}div.permit button div{margin-bottom:200px;color:#000;font-size:34px}input.hidy{opacity:0;position:absolute;left:-200px;top:-200px}\n"], dependencies: [{ kind: "component", type: MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "component", type: MatCardHeader, selector: "mat-card-header" }, { kind: "directive", type: MatCardTitle, selector: "mat-card-title, [mat-card-title], [matCardTitle]" }, { kind: "directive", type: MatCardContent, selector: "mat-card-content" }] });
106
+ }
107
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: PermitFormComponent, decorators: [{
108
+ type: Component,
109
+ args: [{ selector: 'ngx-uik-permit-form', imports: [MatCard, MatCardHeader, MatCardTitle, MatCardContent], template: "<mat-card appearance=\"outlined\">\r\n <mat-card-header>\r\n <mat-card-title>\r\n \u041F\u0440\u0438\u043B\u043E\u0436\u0438\u0442\u0435 \u043F\u0440\u043E\u043F\u0443\u0441\u043A\r\n </mat-card-title>\r\n </mat-card-header>\r\n <mat-card-content>\r\n <div class=\"permit\"></div>\r\n </mat-card-content>\r\n</mat-card>\r\n<input #hidy class=\"hidy\" type=\"text\" (keydown)=\"onKeydown($event)\"/>", styles: [":host{display:flex;justify-content:center;margin:32px 0}.mat-mdc-form-field{width:100%;min-width:300px}mat-card-title,mat-card-content{display:flex;justify-content:center}mat-card-content{font-size:16px}div.permit{border:none;width:300px;background-size:300px;height:180px}div.permit button div{margin-bottom:200px;color:#000;font-size:34px}input.hidy{opacity:0;position:absolute;left:-200px;top:-200px}\n"] }]
110
+ }], propDecorators: { hidy: [{ type: i0.ViewChild, args: ['hidy', { isSignal: true }] }], submitted: [{ type: i0.Output, args: ["submitted"] }], mouseHandling: [{
111
+ type: HostListener,
112
+ args: ['document:mouseup', ['$event']]
113
+ }] } });
114
+
115
+ class AvatarService {
116
+ baseRoute = 'common/human/';
117
+ http = inject(HttpClient);
118
+ getAvatarById(idHuman) {
119
+ return this.http.get(this.baseRoute + idHuman + '/avatar', { responseType: 'arraybuffer' });
120
+ }
121
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AvatarService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
122
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AvatarService, providedIn: 'root' });
123
+ }
124
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AvatarService, decorators: [{
125
+ type: Injectable,
126
+ args: [{
127
+ providedIn: 'root'
128
+ }]
129
+ }] });
130
+
131
+ class BaseMatChipComponent {
132
+ // Все элементы
133
+ items = input([], ...(ngDevMode ? [{ debugName: "items" }] : []));
134
+ // Выбранные элементы, ключи (ChipItem.value)
135
+ selectedItemsInput = input([], ...(ngDevMode ? [{ debugName: "selectedItemsInput" }] : []));
136
+ // Заголовок
137
+ title = input('', ...(ngDevMode ? [{ debugName: "title" }] : []));
138
+ // Событие изменения выбранных элементов
139
+ selectedItemsChange = output();
140
+ input = viewChild('input', ...(ngDevMode ? [{ debugName: "input" }] : []));
141
+ separatorKeysCodes = [ENTER, COMMA];
142
+ inputCtrl = new FormControl();
143
+ filteredItems$;
144
+ selectedItems = [];
145
+ constructor() {
146
+ effect(() => {
147
+ if (this.items().length > 0) {
148
+ this.filteredItems$ = this.inputCtrl.valueChanges.pipe(startWith(null), map(item => (item ? this._filter(item) : this.items().slice())));
149
+ }
150
+ });
151
+ effect(() => {
152
+ if (this.selectedItemsInput())
153
+ this.selectedItems = this.items().filter(s => this.selectedItemsInput().includes(s.value));
154
+ });
155
+ }
156
+ remove(value) {
157
+ this.selectedItems = [...this.selectedItems];
158
+ const index = this.selectedItems.map(i => i.value).indexOf(value);
159
+ if (index >= 0) {
160
+ this.selectedItems.splice(index, 1);
161
+ this.selectedItemsChange.emit(this.selectedItems.map(i => i.value));
162
+ }
163
+ }
164
+ selected(event) {
165
+ this.selectedItems = [...this.selectedItems];
166
+ const item = this.items().find(s => s.value == event.option.value);
167
+ if (item) {
168
+ this.selectedItems.push(item);
169
+ }
170
+ this.selectedItemsChange.emit(this.selectedItems.map(i => i.value));
171
+ const inputValue = this.input();
172
+ if (inputValue)
173
+ inputValue.nativeElement.value = '';
174
+ this.inputCtrl.setValue(null);
175
+ }
176
+ _filter(value) {
177
+ const filterValue = value.toLowerCase();
178
+ return this.items().filter(item => item.viewValue.toLowerCase().includes(filterValue));
179
+ }
180
+ onCloseClick($event) {
181
+ $event.stopPropagation();
182
+ this.selectedItemsChange.emit([]);
183
+ }
184
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: BaseMatChipComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
185
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: BaseMatChipComponent, isStandalone: true, selector: "ngx-uik-chip-input-autocomplete", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, selectedItemsInput: { classPropertyName: "selectedItemsInput", publicName: "selectedItemsInput", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedItemsChange: "selectedItemsChange" }, viewQueries: [{ propertyName: "input", first: true, predicate: ["input"], descendants: true, isSignal: true }], ngImport: i0, template: "<mat-form-field class=\"chip-list\" appearance=\"fill\">\r\n <mat-label>{{ title() }}</mat-label>\r\n <mat-chip-grid #chipList aria-label=\"'\u0412\u044B\u0431\u043E\u0440 '+title()\">\r\n @for (item of selectedItems; track item) {\r\n <mat-chip-row color=\"primary\"\r\n (removed)=\"remove(item.value)\">\r\n {{ item.viewValue }}\r\n <button matChipRemove>\r\n <mat-icon>cancel</mat-icon>\r\n </button>\r\n </mat-chip-row>\r\n }\r\n </mat-chip-grid>\r\n <input\r\n #input\r\n [placeholder]=\"'\u0412\u0432\u0435\u0434\u0438\u0442\u0435 '+title()+'...'\"\r\n [formControl]=\"inputCtrl\"\r\n [matAutocomplete]=\"auto\"\r\n [matChipInputFor]=\"chipList\"\r\n [matChipInputSeparatorKeyCodes]=\"separatorKeysCodes\"\r\n >\r\n <mat-autocomplete #auto=\"matAutocomplete\" (optionSelected)=\"selected($event)\">\r\n @for (item of filteredItems$ | async; track item) {\r\n <mat-option [value]=\"item.value\"\r\n [disabled]=\"selectedItemsInput()?.includes(item.value)\">\r\n {{ item.viewValue }}\r\n </mat-option>\r\n }\r\n </mat-autocomplete>\r\n @if (selectedItems.length > 0) {\r\n <button matSuffix mat-icon-button aria-label=\"Clear\" (click)=\"onCloseClick($event)\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n }\r\n</mat-form-field>\r\n", styles: [".chip-list{width:100%}\n"], dependencies: [{ kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.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: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatAutocompleteModule }, { kind: "component", type: i2.MatAutocomplete, selector: "mat-autocomplete", inputs: ["aria-label", "aria-labelledby", "displayWith", "autoActiveFirstOption", "autoSelectActiveOption", "requireSelection", "panelWidth", "disableRipple", "class", "hideSingleSelectionIndicator"], outputs: ["optionSelected", "opened", "closed", "optionActivated"], exportAs: ["matAutocomplete"] }, { kind: "component", type: i2.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: i2.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", inputs: ["matAutocomplete", "matAutocompletePosition", "matAutocompleteConnectedTo", "autocomplete", "matAutocompleteDisabled"], exportAs: ["matAutocompleteTrigger"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatChipsModule }, { kind: "component", type: i3.MatChipGrid, selector: "mat-chip-grid", inputs: ["disabled", "placeholder", "required", "value", "errorStateMatcher"], outputs: ["change", "valueChange"] }, { kind: "directive", type: i3.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputFor", "matChipInputAddOnBlur", "matChipInputSeparatorKeyCodes", "placeholder", "id", "disabled", "readonly", "matChipInputDisabledInteractive"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }, { kind: "directive", type: i3.MatChipRemove, selector: "[matChipRemove]" }, { kind: "component", type: i3.MatChipRow, selector: "mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]", inputs: ["editable"], outputs: ["edited"] }, { kind: "directive", type: MatLabel, selector: "mat-label" }, { kind: "pipe", type: AsyncPipe, name: "async" }] });
186
+ }
187
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: BaseMatChipComponent, decorators: [{
188
+ type: Component,
189
+ args: [{ selector: 'ngx-uik-chip-input-autocomplete', imports: [MatFormField, AsyncPipe, FormsModule, ReactiveFormsModule, MatAutocompleteModule, MatIcon, MatOption,
190
+ MatChipsModule, MatLabel], template: "<mat-form-field class=\"chip-list\" appearance=\"fill\">\r\n <mat-label>{{ title() }}</mat-label>\r\n <mat-chip-grid #chipList aria-label=\"'\u0412\u044B\u0431\u043E\u0440 '+title()\">\r\n @for (item of selectedItems; track item) {\r\n <mat-chip-row color=\"primary\"\r\n (removed)=\"remove(item.value)\">\r\n {{ item.viewValue }}\r\n <button matChipRemove>\r\n <mat-icon>cancel</mat-icon>\r\n </button>\r\n </mat-chip-row>\r\n }\r\n </mat-chip-grid>\r\n <input\r\n #input\r\n [placeholder]=\"'\u0412\u0432\u0435\u0434\u0438\u0442\u0435 '+title()+'...'\"\r\n [formControl]=\"inputCtrl\"\r\n [matAutocomplete]=\"auto\"\r\n [matChipInputFor]=\"chipList\"\r\n [matChipInputSeparatorKeyCodes]=\"separatorKeysCodes\"\r\n >\r\n <mat-autocomplete #auto=\"matAutocomplete\" (optionSelected)=\"selected($event)\">\r\n @for (item of filteredItems$ | async; track item) {\r\n <mat-option [value]=\"item.value\"\r\n [disabled]=\"selectedItemsInput()?.includes(item.value)\">\r\n {{ item.viewValue }}\r\n </mat-option>\r\n }\r\n </mat-autocomplete>\r\n @if (selectedItems.length > 0) {\r\n <button matSuffix mat-icon-button aria-label=\"Clear\" (click)=\"onCloseClick($event)\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n }\r\n</mat-form-field>\r\n", styles: [".chip-list{width:100%}\n"] }]
191
+ }], ctorParameters: () => [], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], selectedItemsInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedItemsInput", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], selectedItemsChange: [{ type: i0.Output, args: ["selectedItemsChange"] }], input: [{ type: i0.ViewChild, args: ['input', { isSignal: true }] }] } });
192
+
193
+ function dateFormat(date) {
194
+ if (date)
195
+ return moment(date).format("YYYY-MM-DD");
196
+ else
197
+ return '';
198
+ }
199
+
200
+ // See the Moment.js docs for the meaning of these formats:
201
+ // https://momentjs.com/docs/#/displaying/format/
202
+ const MY_FORMATS = {
203
+ parse: {
204
+ dateInput: 'DD.MM.YYYY',
205
+ },
206
+ display: {
207
+ dateInput: 'DD.MM.YYYY',
208
+ monthYearLabel: 'MMM YYYY',
209
+ dateA11yLabel: 'LL',
210
+ monthYearA11yLabel: 'MMMM YYYY',
211
+ },
212
+ };
213
+
214
+ class DateRangeInputComponent {
215
+ label = input('', ...(ngDevMode ? [{ debugName: "label" }] : []));
216
+ dateRange = input({ begin: '', end: '' }, ...(ngDevMode ? [{ debugName: "dateRange" }] : []));
217
+ // eslint-disable-next-line no-magic-numbers
218
+ minDate = input(new Date(2020, 0, 1), ...(ngDevMode ? [{ debugName: "minDate" }] : []));
219
+ clearInput = input(null, ...(ngDevMode ? [{ debugName: "clearInput" }] : []));
220
+ required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : []));
221
+ dateRangeChange = output();
222
+ form = new FormGroup({
223
+ begin: new FormControl(),
224
+ end: new FormControl(),
225
+ });
226
+ subscription = new Subscription();
227
+ constructor() {
228
+ effect(() => {
229
+ if (this.clearInput())
230
+ this.form.reset();
231
+ });
232
+ effect(() => {
233
+ const value = this.dateRange();
234
+ if (this.form) {
235
+ this.form.controls['begin'].setValue(value.begin ? new Date(value.begin) : null);
236
+ this.form.controls['end'].setValue(value.end ? new Date(value.begin) : null);
237
+ }
238
+ this.dateRangeChange.emit(this.rangeToDateDateRange(this.form.value));
239
+ });
240
+ }
241
+ ngOnInit() {
242
+ if (this.required()) {
243
+ this.form.controls['begin'].addValidators(Validators.required);
244
+ this.form.controls['end'].addValidators(Validators.required);
245
+ }
246
+ // подписка на изменение периода
247
+ this.form.valueChanges
248
+ .pipe(
249
+ // eslint-disable-next-line no-magic-numbers
250
+ debounceTime(500), distinctUntilChanged())
251
+ .subscribe({
252
+ next: range => {
253
+ if (this.required()) {
254
+ if (range.begin && range.end) {
255
+ this.dateRangeChange.emit(this.rangeToDateDateRange(range));
256
+ }
257
+ }
258
+ else {
259
+ this.dateRangeChange.emit(this.rangeToDateDateRange(range));
260
+ }
261
+ }
262
+ });
263
+ }
264
+ ngOnDestroy() {
265
+ if (this.subscription)
266
+ this.subscription.unsubscribe();
267
+ }
268
+ rangeToDateDateRange(range) {
269
+ return {
270
+ begin: range.begin ? dateFormat(range.begin) : '',
271
+ end: range.end ? dateFormat(range.end) : ''
272
+ };
273
+ }
274
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DateRangeInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
275
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.0", type: DateRangeInputComponent, isStandalone: true, selector: "ngx-uik-date-range-input", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, dateRange: { classPropertyName: "dateRange", publicName: "dateRange", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, clearInput: { classPropertyName: "clearInput", publicName: "clearInput", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { dateRangeChange: "dateRangeChange" }, providers: [
276
+ { provide: MAT_DATE_LOCALE, useValue: 'ru' },
277
+ { provide: MAT_DATE_FORMATS, useValue: MY_FORMATS },
278
+ ], ngImport: i0, template: "<mat-form-field appearance=\"fill\">\r\n <mat-label>{{label()}}</mat-label>\r\n <mat-date-range-input\r\n [rangePicker]=\"picker\"\r\n [formGroup]=\"form\"\r\n [min]=\"minDate()\">\r\n <input matStartDate formControlName=\"begin\" placeholder=\"\u0414\u0430\u0442\u0430 \u043D\u0430\u0447\u0430\u043B\u0430\">\r\n <input matEndDate formControlName=\"end\" placeholder=\"\u0414\u0430\u0442\u0430 \u043E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u044F\">\r\n </mat-date-range-input>\r\n <mat-datepicker-toggle matIconSuffix [for]=\"picker\"></mat-datepicker-toggle>\r\n <mat-date-range-picker #picker></mat-date-range-picker>\r\n <mat-error>\u0423\u043A\u0430\u0436\u0438\u0442\u0435 \u043F\u0435\u0440\u0438\u043E\u0434</mat-error>\r\n</mat-form-field>\r\n\r\n", styles: ["mat-form-field{margin-right:16px}\n"], dependencies: [{ kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: MatLabel, selector: "mat-label" }, { kind: "component", type: MatDateRangeInput, selector: "mat-date-range-input", inputs: ["rangePicker", "required", "dateFilter", "min", "max", "disabled", "separator", "comparisonStart", "comparisonEnd"], exportAs: ["matDateRangeInput"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.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: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: MatStartDate, selector: "input[matStartDate]", outputs: ["dateChange", "dateInput"] }, { kind: "directive", type: MatEndDate, selector: "input[matEndDate]", outputs: ["dateChange", "dateInput"] }, { kind: "component", type: MatDatepickerToggle, selector: "mat-datepicker-toggle", inputs: ["for", "tabIndex", "aria-label", "disabled", "disableRipple"], exportAs: ["matDatepickerToggle"] }, { kind: "directive", type: MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "component", type: MatDateRangePicker, selector: "mat-date-range-picker", exportAs: ["matDateRangePicker"] }, { kind: "directive", type: MatError, selector: "mat-error, [matError]", inputs: ["id"] }] });
279
+ }
280
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DateRangeInputComponent, decorators: [{
281
+ type: Component,
282
+ args: [{ selector: 'ngx-uik-date-range-input', imports: [MatFormField, MatLabel, MatDateRangeInput, FormsModule, ReactiveFormsModule, MatStartDate, MatEndDate,
283
+ MatDatepickerToggle, MatSuffix, MatDateRangePicker, MatError], providers: [
284
+ { provide: MAT_DATE_LOCALE, useValue: 'ru' },
285
+ { provide: MAT_DATE_FORMATS, useValue: MY_FORMATS },
286
+ ], template: "<mat-form-field appearance=\"fill\">\r\n <mat-label>{{label()}}</mat-label>\r\n <mat-date-range-input\r\n [rangePicker]=\"picker\"\r\n [formGroup]=\"form\"\r\n [min]=\"minDate()\">\r\n <input matStartDate formControlName=\"begin\" placeholder=\"\u0414\u0430\u0442\u0430 \u043D\u0430\u0447\u0430\u043B\u0430\">\r\n <input matEndDate formControlName=\"end\" placeholder=\"\u0414\u0430\u0442\u0430 \u043E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u044F\">\r\n </mat-date-range-input>\r\n <mat-datepicker-toggle matIconSuffix [for]=\"picker\"></mat-datepicker-toggle>\r\n <mat-date-range-picker #picker></mat-date-range-picker>\r\n <mat-error>\u0423\u043A\u0430\u0436\u0438\u0442\u0435 \u043F\u0435\u0440\u0438\u043E\u0434</mat-error>\r\n</mat-form-field>\r\n\r\n", styles: ["mat-form-field{margin-right:16px}\n"] }]
287
+ }], ctorParameters: () => [], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], dateRange: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateRange", required: false }] }], minDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "minDate", required: false }] }], clearInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearInput", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], dateRangeChange: [{ type: i0.Output, args: ["dateRangeChange"] }] } });
288
+
289
+ class DialogComponent {
290
+ data = inject(MAT_DIALOG_DATA);
291
+ dialogRef = inject((MatDialogRef));
292
+ constructor() {
293
+ if (!this.data.title) {
294
+ this.data.title = 'Подтверждение';
295
+ }
296
+ if (!this.data.btnNoTitle) {
297
+ this.data.btnNoTitle = 'Нет';
298
+ }
299
+ if (!this.data.btnYesTitle) {
300
+ this.data.btnYesTitle = 'Да';
301
+ }
302
+ }
303
+ onNoClick() {
304
+ this.dialogRef.close();
305
+ }
306
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
307
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.0", type: DialogComponent, isStandalone: true, selector: "ngx-uik-dialog", ngImport: i0, template: "<h1 mat-dialog-title>{{ data.title }}</h1>\r\n<div mat-dialog-content>\r\n <div style=\"white-space: pre-line\">{{ data.message }}</div>\r\n</div>\r\n<div mat-dialog-actions align=\"end\">\r\n <button mat-raised-button (click)=\"onNoClick()\" cdkFocusInitial>{{ data.btnNoTitle }}</button>\r\n <button mat-raised-button color=\"warn\" [mat-dialog-close]=\"data.id\">{{ data.btnYesTitle }}</button>\r\n</div>\r\n\r\n", styles: [""], dependencies: [{ kind: "directive", type: MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "directive", type: MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "component", type: MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "directive", type: MatDialogClose, selector: "[mat-dialog-close], [matDialogClose]", inputs: ["aria-label", "type", "mat-dialog-close", "matDialogClose"], exportAs: ["matDialogClose"] }] });
308
+ }
309
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DialogComponent, decorators: [{
310
+ type: Component,
311
+ args: [{ selector: 'ngx-uik-dialog', imports: [MatDialogTitle, MatDialogContent, MatDialogActions, MatButton, MatDialogClose], template: "<h1 mat-dialog-title>{{ data.title }}</h1>\r\n<div mat-dialog-content>\r\n <div style=\"white-space: pre-line\">{{ data.message }}</div>\r\n</div>\r\n<div mat-dialog-actions align=\"end\">\r\n <button mat-raised-button (click)=\"onNoClick()\" cdkFocusInitial>{{ data.btnNoTitle }}</button>\r\n <button mat-raised-button color=\"warn\" [mat-dialog-close]=\"data.id\">{{ data.btnYesTitle }}</button>\r\n</div>\r\n\r\n" }]
312
+ }], ctorParameters: () => [] });
313
+
314
+ var DialogAction;
315
+ (function (DialogAction) {
316
+ DialogAction["Add"] = "\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C";
317
+ DialogAction["Edit"] = "\u0418\u0437\u043C\u0435\u043D\u0438\u0442\u044C";
318
+ DialogAction["Delete"] = "\u0423\u0434\u0430\u043B\u0438\u0442\u044C";
319
+ DialogAction["None"] = "";
320
+ })(DialogAction || (DialogAction = {}));
321
+
322
+ class EmptyComponent {
323
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: EmptyComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
324
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.0", type: EmptyComponent, isStandalone: true, selector: "ng-component", ngImport: i0, template: '' // пустой шаблон, так как гуард сразу уводит пользователя со страницы
325
+ , isInline: true });
326
+ }
327
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: EmptyComponent, decorators: [{
328
+ type: Component,
329
+ args: [{
330
+ standalone: true,
331
+ template: '' // пустой шаблон, так как гуард сразу уводит пользователя со страницы
332
+ }]
333
+ }] });
334
+
335
+ class BaseToolbarComponent {
336
+ // Роли для кнопок
337
+ rolesNewBtn = input([], ...(ngDevMode ? [{ debugName: "rolesNewBtn" }] : []));
338
+ rolesEditBtn = input([], ...(ngDevMode ? [{ debugName: "rolesEditBtn" }] : []));
339
+ rolesRemoveBtn = input([], ...(ngDevMode ? [{ debugName: "rolesRemoveBtn" }] : []));
340
+ rolesCopyBtn = input([], ...(ngDevMode ? [{ debugName: "rolesCopyBtn" }] : []));
341
+ rolesExcelBtn = input([], ...(ngDevMode ? [{ debugName: "rolesExcelBtn" }] : []));
342
+ rolesCsvBtn = input([], ...(ngDevMode ? [{ debugName: "rolesCsvBtn" }] : []));
343
+ rolesPdfBtn = input([], ...(ngDevMode ? [{ debugName: "rolesPdfBtn" }] : []));
344
+ rolesPrintBtn = input([], ...(ngDevMode ? [{ debugName: "rolesPrintBtn" }] : []));
345
+ rolesRefreshBtn = input([], ...(ngDevMode ? [{ debugName: "rolesRefreshBtn" }] : []));
346
+ rolesClearBtn = input([], ...(ngDevMode ? [{ debugName: "rolesClearBtn" }] : []));
347
+ // Состояния блокировки
348
+ newBtnDisabled = input(false, ...(ngDevMode ? [{ debugName: "newBtnDisabled" }] : []));
349
+ editBtnDisabled = input(false, ...(ngDevMode ? [{ debugName: "editBtnDisabled" }] : []));
350
+ removeBtnDisabled = input(false, ...(ngDevMode ? [{ debugName: "removeBtnDisabled" }] : []));
351
+ copyBtnDisabled = input(false, ...(ngDevMode ? [{ debugName: "copyBtnDisabled" }] : []));
352
+ excelBtnDisabled = input(false, ...(ngDevMode ? [{ debugName: "excelBtnDisabled" }] : []));
353
+ csvBtnDisabled = input(false, ...(ngDevMode ? [{ debugName: "csvBtnDisabled" }] : []));
354
+ pdfBtnDisabled = input(false, ...(ngDevMode ? [{ debugName: "pdfBtnDisabled" }] : []));
355
+ printBtnDisabled = input(false, ...(ngDevMode ? [{ debugName: "printBtnDisabled" }] : []));
356
+ refreshBtnDisabled = input(false, ...(ngDevMode ? [{ debugName: "refreshBtnDisabled" }] : []));
357
+ clearBtnDisabled = input(false, ...(ngDevMode ? [{ debugName: "clearBtnDisabled" }] : []));
358
+ // Тултипы
359
+ newBtnTooltip = input('Добавить', ...(ngDevMode ? [{ debugName: "newBtnTooltip" }] : []));
360
+ editBtnTooltip = input('Изменить', ...(ngDevMode ? [{ debugName: "editBtnTooltip" }] : []));
361
+ removeBtnTooltip = input('Удалить', ...(ngDevMode ? [{ debugName: "removeBtnTooltip" }] : []));
362
+ copyBtnTooltip = input('Скопировать', ...(ngDevMode ? [{ debugName: "copyBtnTooltip" }] : []));
363
+ excelBtnTooltip = input('Экспортировать в Excel', ...(ngDevMode ? [{ debugName: "excelBtnTooltip" }] : []));
364
+ csvBtnTooltip = input('Экспортировать в Csv', ...(ngDevMode ? [{ debugName: "csvBtnTooltip" }] : []));
365
+ pdfBtnTooltip = input('Экспортировать в Pdf', ...(ngDevMode ? [{ debugName: "pdfBtnTooltip" }] : []));
366
+ printBtnTooltip = input('Печатать', ...(ngDevMode ? [{ debugName: "printBtnTooltip" }] : []));
367
+ refreshBtnTooltip = input('Обновить данные', ...(ngDevMode ? [{ debugName: "refreshBtnTooltip" }] : []));
368
+ clearBtnTooltip = input('Очистить фильтр', ...(ngDevMode ? [{ debugName: "clearBtnTooltip" }] : []));
369
+ /** Список элементов контекстного меню. */
370
+ newBtnOpt = input([], ...(ngDevMode ? [{ debugName: "newBtnOpt" }] : []));
371
+ // События
372
+ clickedNewBtn = output();
373
+ clickedEditBtn = output();
374
+ clickedRemoveBtn = output();
375
+ clickedCopyBtn = output();
376
+ clickedExcelBtn = output();
377
+ clickedCsvBtn = output();
378
+ clickedPdfBtn = output();
379
+ clickedPrintBtn = output();
380
+ clickedRefreshBtn = output();
381
+ clickedClearBtn = output();
382
+ // DI
383
+ authService = inject(AuthService);
384
+ roleService = inject(RoleService);
385
+ isShow(roles) {
386
+ return !this.roleService.isHideElement(roles, this.authService.roles());
387
+ }
388
+ onNewClick() {
389
+ this.clickedNewBtn.emit();
390
+ }
391
+ onEditClick() {
392
+ this.clickedEditBtn.emit();
393
+ }
394
+ onRemoveClick() {
395
+ this.clickedRemoveBtn.emit();
396
+ }
397
+ onCopyClick() {
398
+ this.clickedCopyBtn.emit();
399
+ }
400
+ onExcelClick() {
401
+ this.clickedExcelBtn.emit();
402
+ }
403
+ onCsvClick() {
404
+ this.clickedCsvBtn.emit();
405
+ }
406
+ onPdfClick() {
407
+ this.clickedPdfBtn.emit();
408
+ }
409
+ onPrintClick() {
410
+ this.clickedPrintBtn.emit();
411
+ }
412
+ onRefreshGridClick() {
413
+ this.clickedRefreshBtn.emit();
414
+ }
415
+ onClearClick() {
416
+ this.clickedClearBtn.emit();
417
+ }
418
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: BaseToolbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
419
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: BaseToolbarComponent, isStandalone: true, selector: "ngx-uik-base-toolbar", inputs: { rolesNewBtn: { classPropertyName: "rolesNewBtn", publicName: "rolesNewBtn", isSignal: true, isRequired: false, transformFunction: null }, rolesEditBtn: { classPropertyName: "rolesEditBtn", publicName: "rolesEditBtn", isSignal: true, isRequired: false, transformFunction: null }, rolesRemoveBtn: { classPropertyName: "rolesRemoveBtn", publicName: "rolesRemoveBtn", isSignal: true, isRequired: false, transformFunction: null }, rolesCopyBtn: { classPropertyName: "rolesCopyBtn", publicName: "rolesCopyBtn", isSignal: true, isRequired: false, transformFunction: null }, rolesExcelBtn: { classPropertyName: "rolesExcelBtn", publicName: "rolesExcelBtn", isSignal: true, isRequired: false, transformFunction: null }, rolesCsvBtn: { classPropertyName: "rolesCsvBtn", publicName: "rolesCsvBtn", isSignal: true, isRequired: false, transformFunction: null }, rolesPdfBtn: { classPropertyName: "rolesPdfBtn", publicName: "rolesPdfBtn", isSignal: true, isRequired: false, transformFunction: null }, rolesPrintBtn: { classPropertyName: "rolesPrintBtn", publicName: "rolesPrintBtn", isSignal: true, isRequired: false, transformFunction: null }, rolesRefreshBtn: { classPropertyName: "rolesRefreshBtn", publicName: "rolesRefreshBtn", isSignal: true, isRequired: false, transformFunction: null }, rolesClearBtn: { classPropertyName: "rolesClearBtn", publicName: "rolesClearBtn", isSignal: true, isRequired: false, transformFunction: null }, newBtnDisabled: { classPropertyName: "newBtnDisabled", publicName: "newBtnDisabled", isSignal: true, isRequired: false, transformFunction: null }, editBtnDisabled: { classPropertyName: "editBtnDisabled", publicName: "editBtnDisabled", isSignal: true, isRequired: false, transformFunction: null }, removeBtnDisabled: { classPropertyName: "removeBtnDisabled", publicName: "removeBtnDisabled", isSignal: true, isRequired: false, transformFunction: null }, copyBtnDisabled: { classPropertyName: "copyBtnDisabled", publicName: "copyBtnDisabled", isSignal: true, isRequired: false, transformFunction: null }, excelBtnDisabled: { classPropertyName: "excelBtnDisabled", publicName: "excelBtnDisabled", isSignal: true, isRequired: false, transformFunction: null }, csvBtnDisabled: { classPropertyName: "csvBtnDisabled", publicName: "csvBtnDisabled", isSignal: true, isRequired: false, transformFunction: null }, pdfBtnDisabled: { classPropertyName: "pdfBtnDisabled", publicName: "pdfBtnDisabled", isSignal: true, isRequired: false, transformFunction: null }, printBtnDisabled: { classPropertyName: "printBtnDisabled", publicName: "printBtnDisabled", isSignal: true, isRequired: false, transformFunction: null }, refreshBtnDisabled: { classPropertyName: "refreshBtnDisabled", publicName: "refreshBtnDisabled", isSignal: true, isRequired: false, transformFunction: null }, clearBtnDisabled: { classPropertyName: "clearBtnDisabled", publicName: "clearBtnDisabled", isSignal: true, isRequired: false, transformFunction: null }, newBtnTooltip: { classPropertyName: "newBtnTooltip", publicName: "newBtnTooltip", isSignal: true, isRequired: false, transformFunction: null }, editBtnTooltip: { classPropertyName: "editBtnTooltip", publicName: "editBtnTooltip", isSignal: true, isRequired: false, transformFunction: null }, removeBtnTooltip: { classPropertyName: "removeBtnTooltip", publicName: "removeBtnTooltip", isSignal: true, isRequired: false, transformFunction: null }, copyBtnTooltip: { classPropertyName: "copyBtnTooltip", publicName: "copyBtnTooltip", isSignal: true, isRequired: false, transformFunction: null }, excelBtnTooltip: { classPropertyName: "excelBtnTooltip", publicName: "excelBtnTooltip", isSignal: true, isRequired: false, transformFunction: null }, csvBtnTooltip: { classPropertyName: "csvBtnTooltip", publicName: "csvBtnTooltip", isSignal: true, isRequired: false, transformFunction: null }, pdfBtnTooltip: { classPropertyName: "pdfBtnTooltip", publicName: "pdfBtnTooltip", isSignal: true, isRequired: false, transformFunction: null }, printBtnTooltip: { classPropertyName: "printBtnTooltip", publicName: "printBtnTooltip", isSignal: true, isRequired: false, transformFunction: null }, refreshBtnTooltip: { classPropertyName: "refreshBtnTooltip", publicName: "refreshBtnTooltip", isSignal: true, isRequired: false, transformFunction: null }, clearBtnTooltip: { classPropertyName: "clearBtnTooltip", publicName: "clearBtnTooltip", isSignal: true, isRequired: false, transformFunction: null }, newBtnOpt: { classPropertyName: "newBtnOpt", publicName: "newBtnOpt", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clickedNewBtn: "clickedNewBtn", clickedEditBtn: "clickedEditBtn", clickedRemoveBtn: "clickedRemoveBtn", clickedCopyBtn: "clickedCopyBtn", clickedExcelBtn: "clickedExcelBtn", clickedCsvBtn: "clickedCsvBtn", clickedPdfBtn: "clickedPdfBtn", clickedPrintBtn: "clickedPrintBtn", clickedRefreshBtn: "clickedRefreshBtn", clickedClearBtn: "clickedClearBtn" }, ngImport: i0, template: "<mat-toolbar>\r\n @if (isShow(rolesNewBtn())) {\r\n @if (newBtnOpt() && newBtnOpt().length > 0) {\r\n <button [disabled]=\"newBtnDisabled()\" [matMenuTriggerFor]=\"menuNewBtn\"\r\n mat-icon-button [matTooltip]=\"newBtnTooltip()\">\r\n <mat-icon>add</mat-icon>\r\n </button>\r\n <mat-menu #menuNewBtn=\"matMenu\">\r\n @for (menuItem of newBtnOpt(); track menuItem) {\r\n @if (menuItem.title === '-' && !(menuItem.hideFn ? menuItem.hideFn(\"\") : menuItem.hide)) {\r\n <mat-divider></mat-divider>\r\n }\r\n @if (menuItem.title !== '-' && !(menuItem.hideFn ? menuItem.hideFn(\"\") : menuItem.hide)) {\r\n <button mat-menu-item\r\n (click)=\"menuItem.onClickFn ? menuItem.onClickFn('') : ''\"\r\n [disabled]=\"menuItem.disabledFn ? menuItem.disabledFn('') : menuItem.disabled\">\r\n @if (menuItem.icon) {\r\n <mat-icon>{{menuItem.icon}}</mat-icon>\r\n }\r\n {{ menuItem.title }}\r\n </button>\r\n }\r\n }\r\n </mat-menu>\r\n } \r\n @else {\r\n <button [disabled]=\"newBtnDisabled()\" (click)=\"onNewClick()\"\r\n mat-icon-button routerLink=\"new\" routerLinkActive=\"active\" [matTooltip]=\"newBtnTooltip()\">\r\n <mat-icon>add</mat-icon>\r\n </button>\r\n }\r\n }\r\n\r\n @if (isShow(rolesEditBtn())) {\r\n <button [disabled]=\"editBtnDisabled()\" (click)=\"onEditClick()\"\r\n mat-icon-button routerLink=\"edit\" color=\"primary\" routerLinkActive=\"active\" [matTooltip]=\"editBtnTooltip()\">\r\n <mat-icon>edit</mat-icon>\r\n </button>\r\n }\r\n @if (isShow(rolesRemoveBtn())) {\r\n <button [disabled]=\"removeBtnDisabled()\" (click)=\"onRemoveClick()\"\r\n mat-icon-button routerLink=\"delete\" color=\"warn\" routerLinkActive=\"active\" [matTooltip]=\"removeBtnTooltip()\">\r\n <mat-icon>remove</mat-icon>\r\n </button>\r\n }\r\n @if (isShow(rolesCopyBtn())) {\r\n <button [disabled]=\"copyBtnDisabled()\" (click)=\"onCopyClick()\"\r\n mat-icon-button routerLink=\"delete\" routerLinkActive=\"active\" [matTooltip]=\"copyBtnTooltip()\">\r\n <mat-icon>content_copy</mat-icon>\r\n </button>\r\n }\r\n @if (isShow(rolesExcelBtn())) {\r\n <button [disabled]=\"excelBtnDisabled()\" (click)=\"onExcelClick()\"\r\n mat-icon-button routerLink=\"excel\" routerLinkActive=\"active\" [matTooltip]=\"excelBtnTooltip()\">\r\n <mat-icon class=\"material-icons-outlined\">explicit</mat-icon>\r\n </button>\r\n }\r\n @if (isShow(rolesCsvBtn())) {\r\n <button [disabled]=\"csvBtnDisabled()\" (click)=\"onCsvClick()\"\r\n mat-icon-button routerLink=\"csv\" routerLinkActive=\"active\" [matTooltip]=\"csvBtnTooltip()\">\r\n <mat-icon class=\"material-icons-outlined\">download</mat-icon>\r\n </button>\r\n }\r\n @if (isShow(rolesPdfBtn())) {\r\n <button [disabled]=\"pdfBtnDisabled()\" (click)=\"onPdfClick()\"\r\n mat-icon-button routerLink=\"pdf\" routerLinkActive=\"active\" [matTooltip]=\"pdfBtnTooltip()\">\r\n <mat-icon class=\"material-icons-outlined\">picture_as_pdf</mat-icon>\r\n </button>\r\n }\r\n @if (isShow(rolesPrintBtn())) {\r\n <button [disabled]=\"printBtnDisabled()\" (click)=\"onPrintClick()\"\r\n mat-icon-button routerLink=\"print\" routerLinkActive=\"active\" [matTooltip]=\"printBtnTooltip()\">\r\n <mat-icon class=\"material-icons-outlined\">print_outline</mat-icon>\r\n </button>\r\n }\r\n @if (isShow(rolesRefreshBtn())) {\r\n <button [disabled]=\"refreshBtnDisabled()\" (click)=\"onRefreshGridClick()\"\r\n mat-icon-button routerLink=\"refresh\" routerLinkActive=\"active\" [matTooltip]=\"refreshBtnTooltip()\">\r\n <mat-icon>refresh</mat-icon>\r\n </button>\r\n }\r\n @if (isShow(rolesClearBtn())) {\r\n <button [disabled]=\"clearBtnDisabled()\" (click)=\"onClearClick()\"\r\n mat-icon-button routerLink=\"clear\" routerLinkActive=\"active\" [matTooltip]=\"clearBtnTooltip()\">\r\n <mat-icon>clear</mat-icon>\r\n </button>\r\n }\r\n</mat-toolbar>\r\n", styles: [""], dependencies: [{ kind: "component", type: MatToolbar, selector: "mat-toolbar", inputs: ["color"], exportAs: ["matToolbar"] }, { kind: "component", type: MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "directive", type: MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "component", type: MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }] });
420
+ }
421
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: BaseToolbarComponent, decorators: [{
422
+ type: Component,
423
+ args: [{ selector: 'ngx-uik-base-toolbar', imports: [
424
+ MatToolbar,
425
+ MatIconButton,
426
+ MatTooltip,
427
+ MatIcon,
428
+ MatMenu,
429
+ MatDivider,
430
+ MatMenuTrigger,
431
+ MatMenuItem,
432
+ ], template: "<mat-toolbar>\r\n @if (isShow(rolesNewBtn())) {\r\n @if (newBtnOpt() && newBtnOpt().length > 0) {\r\n <button [disabled]=\"newBtnDisabled()\" [matMenuTriggerFor]=\"menuNewBtn\"\r\n mat-icon-button [matTooltip]=\"newBtnTooltip()\">\r\n <mat-icon>add</mat-icon>\r\n </button>\r\n <mat-menu #menuNewBtn=\"matMenu\">\r\n @for (menuItem of newBtnOpt(); track menuItem) {\r\n @if (menuItem.title === '-' && !(menuItem.hideFn ? menuItem.hideFn(\"\") : menuItem.hide)) {\r\n <mat-divider></mat-divider>\r\n }\r\n @if (menuItem.title !== '-' && !(menuItem.hideFn ? menuItem.hideFn(\"\") : menuItem.hide)) {\r\n <button mat-menu-item\r\n (click)=\"menuItem.onClickFn ? menuItem.onClickFn('') : ''\"\r\n [disabled]=\"menuItem.disabledFn ? menuItem.disabledFn('') : menuItem.disabled\">\r\n @if (menuItem.icon) {\r\n <mat-icon>{{menuItem.icon}}</mat-icon>\r\n }\r\n {{ menuItem.title }}\r\n </button>\r\n }\r\n }\r\n </mat-menu>\r\n } \r\n @else {\r\n <button [disabled]=\"newBtnDisabled()\" (click)=\"onNewClick()\"\r\n mat-icon-button routerLink=\"new\" routerLinkActive=\"active\" [matTooltip]=\"newBtnTooltip()\">\r\n <mat-icon>add</mat-icon>\r\n </button>\r\n }\r\n }\r\n\r\n @if (isShow(rolesEditBtn())) {\r\n <button [disabled]=\"editBtnDisabled()\" (click)=\"onEditClick()\"\r\n mat-icon-button routerLink=\"edit\" color=\"primary\" routerLinkActive=\"active\" [matTooltip]=\"editBtnTooltip()\">\r\n <mat-icon>edit</mat-icon>\r\n </button>\r\n }\r\n @if (isShow(rolesRemoveBtn())) {\r\n <button [disabled]=\"removeBtnDisabled()\" (click)=\"onRemoveClick()\"\r\n mat-icon-button routerLink=\"delete\" color=\"warn\" routerLinkActive=\"active\" [matTooltip]=\"removeBtnTooltip()\">\r\n <mat-icon>remove</mat-icon>\r\n </button>\r\n }\r\n @if (isShow(rolesCopyBtn())) {\r\n <button [disabled]=\"copyBtnDisabled()\" (click)=\"onCopyClick()\"\r\n mat-icon-button routerLink=\"delete\" routerLinkActive=\"active\" [matTooltip]=\"copyBtnTooltip()\">\r\n <mat-icon>content_copy</mat-icon>\r\n </button>\r\n }\r\n @if (isShow(rolesExcelBtn())) {\r\n <button [disabled]=\"excelBtnDisabled()\" (click)=\"onExcelClick()\"\r\n mat-icon-button routerLink=\"excel\" routerLinkActive=\"active\" [matTooltip]=\"excelBtnTooltip()\">\r\n <mat-icon class=\"material-icons-outlined\">explicit</mat-icon>\r\n </button>\r\n }\r\n @if (isShow(rolesCsvBtn())) {\r\n <button [disabled]=\"csvBtnDisabled()\" (click)=\"onCsvClick()\"\r\n mat-icon-button routerLink=\"csv\" routerLinkActive=\"active\" [matTooltip]=\"csvBtnTooltip()\">\r\n <mat-icon class=\"material-icons-outlined\">download</mat-icon>\r\n </button>\r\n }\r\n @if (isShow(rolesPdfBtn())) {\r\n <button [disabled]=\"pdfBtnDisabled()\" (click)=\"onPdfClick()\"\r\n mat-icon-button routerLink=\"pdf\" routerLinkActive=\"active\" [matTooltip]=\"pdfBtnTooltip()\">\r\n <mat-icon class=\"material-icons-outlined\">picture_as_pdf</mat-icon>\r\n </button>\r\n }\r\n @if (isShow(rolesPrintBtn())) {\r\n <button [disabled]=\"printBtnDisabled()\" (click)=\"onPrintClick()\"\r\n mat-icon-button routerLink=\"print\" routerLinkActive=\"active\" [matTooltip]=\"printBtnTooltip()\">\r\n <mat-icon class=\"material-icons-outlined\">print_outline</mat-icon>\r\n </button>\r\n }\r\n @if (isShow(rolesRefreshBtn())) {\r\n <button [disabled]=\"refreshBtnDisabled()\" (click)=\"onRefreshGridClick()\"\r\n mat-icon-button routerLink=\"refresh\" routerLinkActive=\"active\" [matTooltip]=\"refreshBtnTooltip()\">\r\n <mat-icon>refresh</mat-icon>\r\n </button>\r\n }\r\n @if (isShow(rolesClearBtn())) {\r\n <button [disabled]=\"clearBtnDisabled()\" (click)=\"onClearClick()\"\r\n mat-icon-button routerLink=\"clear\" routerLinkActive=\"active\" [matTooltip]=\"clearBtnTooltip()\">\r\n <mat-icon>clear</mat-icon>\r\n </button>\r\n }\r\n</mat-toolbar>\r\n" }]
433
+ }], propDecorators: { rolesNewBtn: [{ type: i0.Input, args: [{ isSignal: true, alias: "rolesNewBtn", required: false }] }], rolesEditBtn: [{ type: i0.Input, args: [{ isSignal: true, alias: "rolesEditBtn", required: false }] }], rolesRemoveBtn: [{ type: i0.Input, args: [{ isSignal: true, alias: "rolesRemoveBtn", required: false }] }], rolesCopyBtn: [{ type: i0.Input, args: [{ isSignal: true, alias: "rolesCopyBtn", required: false }] }], rolesExcelBtn: [{ type: i0.Input, args: [{ isSignal: true, alias: "rolesExcelBtn", required: false }] }], rolesCsvBtn: [{ type: i0.Input, args: [{ isSignal: true, alias: "rolesCsvBtn", required: false }] }], rolesPdfBtn: [{ type: i0.Input, args: [{ isSignal: true, alias: "rolesPdfBtn", required: false }] }], rolesPrintBtn: [{ type: i0.Input, args: [{ isSignal: true, alias: "rolesPrintBtn", required: false }] }], rolesRefreshBtn: [{ type: i0.Input, args: [{ isSignal: true, alias: "rolesRefreshBtn", required: false }] }], rolesClearBtn: [{ type: i0.Input, args: [{ isSignal: true, alias: "rolesClearBtn", required: false }] }], newBtnDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "newBtnDisabled", required: false }] }], editBtnDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "editBtnDisabled", required: false }] }], removeBtnDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "removeBtnDisabled", required: false }] }], copyBtnDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "copyBtnDisabled", required: false }] }], excelBtnDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "excelBtnDisabled", required: false }] }], csvBtnDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "csvBtnDisabled", required: false }] }], pdfBtnDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "pdfBtnDisabled", required: false }] }], printBtnDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "printBtnDisabled", required: false }] }], refreshBtnDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "refreshBtnDisabled", required: false }] }], clearBtnDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearBtnDisabled", required: false }] }], newBtnTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "newBtnTooltip", required: false }] }], editBtnTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "editBtnTooltip", required: false }] }], removeBtnTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "removeBtnTooltip", required: false }] }], copyBtnTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "copyBtnTooltip", required: false }] }], excelBtnTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "excelBtnTooltip", required: false }] }], csvBtnTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "csvBtnTooltip", required: false }] }], pdfBtnTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "pdfBtnTooltip", required: false }] }], printBtnTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "printBtnTooltip", required: false }] }], refreshBtnTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "refreshBtnTooltip", required: false }] }], clearBtnTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearBtnTooltip", required: false }] }], newBtnOpt: [{ type: i0.Input, args: [{ isSignal: true, alias: "newBtnOpt", required: false }] }], clickedNewBtn: [{ type: i0.Output, args: ["clickedNewBtn"] }], clickedEditBtn: [{ type: i0.Output, args: ["clickedEditBtn"] }], clickedRemoveBtn: [{ type: i0.Output, args: ["clickedRemoveBtn"] }], clickedCopyBtn: [{ type: i0.Output, args: ["clickedCopyBtn"] }], clickedExcelBtn: [{ type: i0.Output, args: ["clickedExcelBtn"] }], clickedCsvBtn: [{ type: i0.Output, args: ["clickedCsvBtn"] }], clickedPdfBtn: [{ type: i0.Output, args: ["clickedPdfBtn"] }], clickedPrintBtn: [{ type: i0.Output, args: ["clickedPrintBtn"] }], clickedRefreshBtn: [{ type: i0.Output, args: ["clickedRefreshBtn"] }], clickedClearBtn: [{ type: i0.Output, args: ["clickedClearBtn"] }] } });
434
+
435
+ var Action;
436
+ (function (Action) {
437
+ Action["Add"] = "\u0414\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u0438\u0435";
438
+ Action["Edit"] = "\u0418\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u0435";
439
+ })(Action || (Action = {}));
440
+
441
+ class BaseEditClass {
442
+ /** Сервис индикатор загрузки. */
443
+ loaderService = inject(LoaderService);
444
+ /** Сервис уведомлений. */
445
+ notificationService = inject(NotificationService);
446
+ /** Объект для отписки (вызывается метод unsubscribe при уничтожении компонента). */
447
+ subscription = new Subscription();
448
+ ngOnDestroy() {
449
+ this.subscription.unsubscribe();
450
+ }
451
+ onNoClick(event) {
452
+ this.dialogRef?.close(null);
453
+ event.preventDefault(); // иначе сработает onSubmit
454
+ }
455
+ onSubmit() {
456
+ if (this.form) {
457
+ if (this.form.valid) {
458
+ if (this.dialogData)
459
+ Object.keys(this.form.controls).forEach(controlName => this.dialogData.entity[controlName] = this.form?.controls[controlName].value);
460
+ this.dialogRef?.close(this.dialogData);
461
+ }
462
+ else {
463
+ Object.keys(this.form.controls).forEach(controlName => this.form?.controls[controlName].markAsTouched());
464
+ }
465
+ }
466
+ }
467
+ formActionIsAdd() {
468
+ return this.dialogData?.action === Action.Add;
469
+ }
470
+ formActionIsEdit() {
471
+ return this.dialogData?.action === Action.Edit;
472
+ }
473
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: BaseEditClass, deps: [], target: i0.ɵɵFactoryTarget.Directive });
474
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.0", type: BaseEditClass, isStandalone: true, ngImport: i0 });
475
+ }
476
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: BaseEditClass, decorators: [{
477
+ type: Directive
478
+ }] });
479
+
480
+ var EntityAction;
481
+ (function (EntityAction) {
482
+ EntityAction["Init"] = "\u0418\u043D\u0438\u0446\u0438\u0430\u043B\u0438\u0437\u0430\u0446\u0438\u044F";
483
+ EntityAction["Add"] = "\u0414\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u0438\u0435";
484
+ EntityAction["Edit"] = "\u0418\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u0435";
485
+ EntityAction["Delete"] = "\u0423\u0434\u0430\u043B\u0435\u043D\u0438\u0435";
486
+ })(EntityAction || (EntityAction = {}));
487
+
488
+ class BaseFilterClass {
489
+ /** Сервис для работы с LocalStorage. */
490
+ localStorageService = inject(LocalStorageService);
491
+ /** Сервис индикатор загрузки. */
492
+ loaderService = inject(LoaderService);
493
+ /** Сервис уведомлений. */
494
+ notificationService = inject(NotificationService);
495
+ // eslint-disable-next-line no-magic-numbers
496
+ defaultDebounceTime = 500;
497
+ /** Объект для отписки (вызывается метод unsubscribe при уничтожении компонента). */
498
+ subscription = new Subscription();
499
+ constructor() {
500
+ }
501
+ ngOnDestroy() {
502
+ this.subscription.unsubscribe();
503
+ }
504
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: BaseFilterClass, deps: [], target: i0.ɵɵFactoryTarget.Directive });
505
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.0", type: BaseFilterClass, isStandalone: true, ngImport: i0 });
506
+ }
507
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: BaseFilterClass, decorators: [{
508
+ type: Directive
509
+ }], ctorParameters: () => [] });
510
+
511
+ class BaseNavBarMenuClass {
512
+ subscription = new Subscription();
513
+ router = inject(Router);
514
+ ngOnDestroy() {
515
+ if (this.subscription)
516
+ this.subscription.unsubscribe();
517
+ }
518
+ /** Нажата средняя кнопка (открыть ссылку в новой вкладке). */
519
+ onMiddleClick(event, baseUrl, menu) {
520
+ // 1 - Auxiliary button pressed (usually the middle button)
521
+ if (event.button === 1) {
522
+ // event.preventDefault();
523
+ menu.closeMenu();
524
+ const urlTree = this.router.serializeUrl(this.router.createUrlTree([baseUrl]));
525
+ window.open(urlTree, '_blank');
526
+ }
527
+ }
528
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: BaseNavBarMenuClass, deps: [], target: i0.ɵɵFactoryTarget.Directive });
529
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.0", type: BaseNavBarMenuClass, isStandalone: true, ngImport: i0 });
530
+ }
531
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: BaseNavBarMenuClass, decorators: [{
532
+ type: Directive
533
+ }] });
534
+
535
+ class LocalStorageService {
536
+ constructor() { }
537
+ saveData(key, value) {
538
+ localStorage.setItem(key, value);
539
+ }
540
+ getData(key) {
541
+ return localStorage.getItem(key);
542
+ }
543
+ removeData(key) {
544
+ localStorage.removeItem(key);
545
+ }
546
+ clearData() {
547
+ localStorage.clear();
548
+ }
549
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: LocalStorageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
550
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: LocalStorageService, providedIn: 'root' });
551
+ }
552
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: LocalStorageService, decorators: [{
553
+ type: Injectable,
554
+ args: [{
555
+ providedIn: 'root'
556
+ }]
557
+ }], ctorParameters: () => [] });
558
+
559
+ class BasePageClass {
560
+ dialog = inject(MatDialog);
561
+ /** Данные для табличного компонента. */
562
+ data = signal([], ...(ngDevMode ? [{ debugName: "data" }] : []));
563
+ /** Количество записей по фильтру. */
564
+ length = signal(0, ...(ngDevMode ? [{ debugName: "length" }] : []));
565
+ entityService;
566
+ entityType;
567
+ entityEditComponent;
568
+ extraData;
569
+ // eslint-disable-next-line no-magic-numbers
570
+ defaultPageIndex = 0;
571
+ // eslint-disable-next-line no-magic-numbers
572
+ defaultPageSize = 10;
573
+ dialogEditWidth = 'auto';
574
+ dialogRemoveWidth = '400px';
575
+ routeAddress = '';
576
+ /** Сообщение при удалении записи(й). */
577
+ removalMessage = '';
578
+ /** Заголовок страницы. */
579
+ pageTitle = '';
580
+ /**
581
+ * Создание записи: вызывается перед открытием диалога.
582
+ */
583
+ beforeOpenDialogOnNewEvent;
584
+ /**
585
+ * Редактирование записи: вызывается перед открытием диалога.
586
+ */
587
+ beforeOpenDialogOnEditEvent;
588
+ /**
589
+ * Создание записи: вызывается перед сохранением объекта.
590
+ */
591
+ beforeSaveOnNewEvent;
592
+ /**
593
+ * Редактирование записи: вызывается перед сохранением объекта.
594
+ */
595
+ beforeSaveOnEditEvent;
596
+ /**
597
+ * Создание записи: вызывается после сохранения объекта.
598
+ */
599
+ afterSaveOnNewEvent;
600
+ /**
601
+ * Редактирование записи: вызывается после сохранения объекта.
602
+ */
603
+ afterSaveOnEditEvent;
604
+ editorRoles = [];
605
+ executeRoles = [];
606
+ /** Список ролей, для которых скрыть элемент. */
607
+ hideRoles = ['HIDE'];
608
+ /** Загрузка данных. */
609
+ loadData$ = new Subject();
610
+ /** Загрузка количества записей. */
611
+ loadLength$ = new Subject();
612
+ /** Очистка фильтра. */
613
+ clearFilter$ = new Subject();
614
+ /** Очистка фильтра (для очистки присвоить пустой объект '{}'). */
615
+ clearFilter = null;
616
+ /** Разрешен выбор нескольких строк. */
617
+ allowMultiSelect = false;
618
+ /** Выбранные строки в таблице. */
619
+ selected = [];
620
+ /** Состояние сортировки, пагинации. */
621
+ tableState;
622
+ /** Доступность кнопки "Изменить". */
623
+ editBtnDisabled = true;
624
+ /** Доступность кнопки "Удалить". */
625
+ removeBtnDisabled = true;
626
+ /** Разрешено ли отправлять событие rowDoubleClicked при двойном щелчке мышью. */
627
+ dblClickedEventEnable = true;
628
+ // Список элементов контекстного меню.
629
+ opt = [];
630
+ // DI
631
+ router = inject(Router);
632
+ /** Сервис для работы с LocalStorage. */
633
+ localStorageService = inject(LocalStorageService);
634
+ /** Сервис индикатор загрузки. */
635
+ loaderService = inject(LoaderService);
636
+ /** Сервис уведомлений. */
637
+ notificationService = inject(UIKIT_NOTIFICATION_TOKEN);
638
+ /** Объект для отписки (вызывается метод unsubscribe при уничтожении компонента). */
639
+ subscription = new Subscription();
640
+ constructor() {
641
+ this.tableState = {
642
+ sortActive: this.localStorageService.getData(this.constructor.name + 'SortActive') || '',
643
+ sortDirection: (this.localStorageService.getData(this.constructor.name + 'SortDirection') || ''),
644
+ pageIndex: Number(this.localStorageService.getData(this.constructor.name + 'PageIndex')) || this.defaultPageIndex,
645
+ pageSize: Number(this.localStorageService.getData(this.constructor.name + 'PageSize')) || this.defaultPageSize
646
+ };
647
+ }
648
+ ngOnDestroy() {
649
+ this.subscription.unsubscribe();
650
+ }
651
+ subscribeToLoadData(fnGetData, fnGetCount, fnMapEntity) {
652
+ // отменять стримы, созданные ранее
653
+ const subs = this.loadData$
654
+ .pipe(tap(() => this.loaderService.show()), switchMap(() => fnGetData()), map$1(v => fnMapEntity ? v.map(fnMapEntity()) : v))
655
+ .subscribe({
656
+ next: (response) => {
657
+ this.data.set(response);
658
+ this.loaderService.hide();
659
+ },
660
+ error: (error) => {
661
+ this.loaderService.hide();
662
+ console.log(error);
663
+ this.notificationService?.error('Произошла ошибка: ' + error, 0);
664
+ }
665
+ });
666
+ this.subscription?.add(subs);
667
+ const subs2 = this.loadLength$
668
+ .pipe(switchMap(() => fnGetCount()))
669
+ .subscribe({
670
+ next: (response) => {
671
+ this.length.set(response);
672
+ },
673
+ error: (error) => {
674
+ console.log(error);
675
+ this.notificationService.error('Произошла ошибка: ' + error, 0);
676
+ }
677
+ });
678
+ this.subscription?.add(subs2);
679
+ // загрузить данные и количество записей
680
+ this.loadData$.next(null);
681
+ this.loadLength$.next(null);
682
+ }
683
+ onPageChange(pageState) {
684
+ this.tableState.pageIndex = pageState.pageIndex;
685
+ this.tableState.pageSize = pageState.pageSize;
686
+ this.localStorageService.saveData(this.constructor.name + 'PageIndex', pageState.pageIndex.toString());
687
+ this.localStorageService.saveData(this.constructor.name + 'PageSize', pageState.pageSize.toString());
688
+ this.loadData$.next(null);
689
+ this.loadLength$.next(null);
690
+ }
691
+ onSortChange(sortState) {
692
+ this.tableState.sortActive = sortState.sortActive;
693
+ this.tableState.sortDirection = sortState.sortDirection;
694
+ this.localStorageService.saveData(this.constructor.name + 'SortActive', sortState.sortActive);
695
+ this.localStorageService.saveData(this.constructor.name + 'SortDirection', sortState.sortDirection);
696
+ this.loadData$.next(null);
697
+ this.loadLength$.next(null);
698
+ }
699
+ entityFactory(type) {
700
+ return new type();
701
+ }
702
+ /** Событие изменение выбранных записей. */
703
+ onSelectionChange(selected) {
704
+ this.selected = selected;
705
+ this.editBtnDisabledUpdate(this.selected);
706
+ this.removeBtnDisabledUpdate(this.selected);
707
+ }
708
+ /** Обновление доступности кнопки "Изменить" - вызывается при изменении выбранных записей. */
709
+ editBtnDisabledUpdate(selected) {
710
+ this.editBtnDisabled = !(selected && selected.length === 1);
711
+ }
712
+ /** Обновление доступности кнопки "Удалить" - вызывается при изменении выбранных записей. */
713
+ removeBtnDisabledUpdate(selected) {
714
+ this.removeBtnDisabled = !(selected && selected.length > 0);
715
+ }
716
+ /** Событие двойной клик. */
717
+ onRowDoubleClicked() {
718
+ this.editEvent();
719
+ }
720
+ /** Событие создание. */
721
+ newEvent() {
722
+ if (this.entityEditComponent) {
723
+ const data = { action: Action.Add, entity: new this.entityType(null) };
724
+ // Назначить значения полей объекта перед открытием диалога.
725
+ if (this.beforeOpenDialogOnNewEvent) {
726
+ this.beforeOpenDialogOnNewEvent(data.entity, data.extraData);
727
+ }
728
+ // Открытие окна
729
+ const dialogRef = this.openDialog(this.entityEditComponent, data, this.dialog);
730
+ // Обработка закрытия окна
731
+ const subs = dialogRef.afterClosed().subscribe((result) => {
732
+ // Проверка результата
733
+ if (result && result.entity && (Object.keys(result.entity).length !== 0)) {
734
+ // Дополнительные действия перед сохранением объекта.
735
+ if (this.beforeSaveOnNewEvent)
736
+ this.beforeSaveOnNewEvent(result.entity, result.extraData);
737
+ const subs = this.entityService.newObject(result.entity)
738
+ .subscribe({
739
+ next: (obj) => {
740
+ // Дополнительные действия после сохранения объекта.
741
+ if (this.afterSaveOnNewEvent) {
742
+ const callback = () => {
743
+ this.refreshEvent();
744
+ this.notificationService.success('Запись добавлена.');
745
+ };
746
+ this.afterSaveOnNewEvent(callback.bind(this), obj, result.extraData);
747
+ }
748
+ else {
749
+ this.refreshEvent();
750
+ this.notificationService?.success('Запись добавлена.');
751
+ }
752
+ },
753
+ error: (error) => {
754
+ console.log('error', error);
755
+ this.notificationService.error('Произошла ошибка при добавлении записи: ' + error, 0);
756
+ }
757
+ });
758
+ this.subscription.add(subs);
759
+ }
760
+ });
761
+ this.subscription.add(subs);
762
+ // Закрытие окна по нажатию Escape
763
+ const subs2 = dialogRef.keydownEvents().subscribe((event) => {
764
+ if (event.key === 'Escape') {
765
+ dialogRef.close(null);
766
+ }
767
+ });
768
+ this.subscription.add(subs2);
769
+ }
770
+ else {
771
+ this.notificationService.warning('Действие не доступно.');
772
+ }
773
+ }
774
+ /** Событие редактирование. */
775
+ editEvent() {
776
+ if (this.selected && this.selected.length === 1) {
777
+ if (this.entityEditComponent) {
778
+ const data = { action: Action.Edit, entity: this.selected[0] };
779
+ // Назначить значения полей объекта перед открытием диалога.
780
+ if (this.beforeOpenDialogOnEditEvent) {
781
+ this.beforeOpenDialogOnEditEvent(data.entity, data.extraData);
782
+ }
783
+ // Открытие окна
784
+ const dialogRef = this.openDialog(this.entityEditComponent, data, this.dialog);
785
+ // Обработка закрытия окна
786
+ const subs = dialogRef.afterClosed().subscribe((result) => {
787
+ // Проверка результата
788
+ if (result && result.entity && (Object.keys(result.entity).length !== 0)) {
789
+ // Дополнительные действия перед сохранением объекта.
790
+ if (this.beforeSaveOnEditEvent)
791
+ this.beforeSaveOnEditEvent(result.entity, result.extraData);
792
+ const subs = this.entityService.editObject(result.entity)
793
+ .subscribe({
794
+ next: () => {
795
+ // Дополнительные действия после сохранения объекта.
796
+ if (this.afterSaveOnEditEvent) {
797
+ const callback = () => {
798
+ this.refreshEvent();
799
+ this.notificationService.success('Запись изменена.');
800
+ };
801
+ this.afterSaveOnEditEvent(callback.bind(this), result.entity, result.extraData);
802
+ }
803
+ else {
804
+ this.refreshEvent();
805
+ this.notificationService.success('Запись изменена.');
806
+ }
807
+ },
808
+ error: (error) => {
809
+ console.log('error', error);
810
+ this.notificationService.error('Произошла ошибка при изменении записи: ' + error, 0);
811
+ }
812
+ });
813
+ this.subscription.add(subs);
814
+ }
815
+ });
816
+ this.subscription.add(subs);
817
+ // Закрытие окна по нажатию Escape
818
+ const subs2 = dialogRef.keydownEvents().subscribe((event) => {
819
+ if (event.key === 'Escape') {
820
+ dialogRef.close(null);
821
+ }
822
+ });
823
+ this.subscription.add(subs2);
824
+ }
825
+ else {
826
+ this.notificationService.warning('Действие не доступно.');
827
+ }
828
+ }
829
+ }
830
+ /** Событие удаление. */
831
+ removeEvent() {
832
+ // если выбрана запись(и)
833
+ if (this.selected && this.selected.length > 0) {
834
+ const dialogRef = this.openDialogRemoveConfirm(this.removalMessage);
835
+ if (dialogRef) {
836
+ const subs = dialogRef.afterClosed().subscribe((result) => {
837
+ // при подтверждении возвращается 'delete'
838
+ if (result === 'delete') {
839
+ // готовим объект с запросами на удаление
840
+ const sourcesObject = {};
841
+ this.selected.forEach((item, index) => sourcesObject['obj' + index] = this.entityService.deleteObject(item));
842
+ // ждем, когда выполнятся все запросы
843
+ const subs = forkJoin(sourcesObject)
844
+ .subscribe({
845
+ next: () => {
846
+ this.refreshEvent();
847
+ this.notificationService.success('Выбранные записи удалены.');
848
+ },
849
+ error: (error) => {
850
+ console.log('error', error);
851
+ this.notificationService?.error('Произошла ошибка при удалении записи: ' + error, 0);
852
+ }
853
+ });
854
+ this.subscription.add(subs);
855
+ }
856
+ });
857
+ this.subscription.add(subs);
858
+ // Закрытие окна по нажатию Escape
859
+ const subs2 = dialogRef.keydownEvents().subscribe((event) => {
860
+ if (event.key === 'Escape') {
861
+ dialogRef.close(null);
862
+ }
863
+ });
864
+ this.subscription.add(subs2);
865
+ }
866
+ }
867
+ }
868
+ /** Событие обновления данных. */
869
+ refreshEvent() {
870
+ this.loadData$.next(null);
871
+ this.loadLength$.next(null);
872
+ }
873
+ /** Событие очистки фильтра. */
874
+ clearEvent() {
875
+ this.clearFilter$.next(null);
876
+ this.clearFilter = {};
877
+ }
878
+ /** Изменение сообщения об удалении. */
879
+ onRemovalMessageChange(message) {
880
+ this.removalMessage = message;
881
+ }
882
+ /** Изменение заголовка страницы. */
883
+ onPageTitleChange(title) {
884
+ this.pageTitle = title;
885
+ }
886
+ openDialog(entityComponent, data, dialog) {
887
+ // create dialog config
888
+ const dialogConfig = new MatDialogConfig();
889
+ dialogConfig.disableClose = true;
890
+ dialogConfig.autoFocus = true;
891
+ dialogConfig.width = this.dialogEditWidth;
892
+ dialogConfig.data = data;
893
+ dialogConfig.panelClass = this.entityType.name + '-edit-dialog';
894
+ // return dialog
895
+ return dialog.open(entityComponent, dialogConfig);
896
+ }
897
+ openDialogRemoveConfirm(removalMessage) {
898
+ let message = 'Вы хотите удалить ';
899
+ message += removalMessage ?
900
+ removalMessage :
901
+ this.allowMultiSelect ? `выбранные записи (${this.selected.length})?` : 'выбранную запись?';
902
+ return this.dialog.open(DialogComponent, {
903
+ width: this.dialogRemoveWidth,
904
+ data: {
905
+ id: 'delete',
906
+ title: 'Подтверждение',
907
+ message: message,
908
+ btnNoTitle: 'Отмена',
909
+ btnYesTitle: 'Удалить'
910
+ }
911
+ });
912
+ }
913
+ // contextMenu: При щелчке ПКМ открыть в новой вкладке.
914
+ onMiddleButton(baseUrl, queryParamName, queryParamValue) {
915
+ return ($event, item, contextMenu) => {
916
+ // Нажата средняя кнопка (в новой вкладке).
917
+ // 1 - Auxiliary button pressed (usually the middle button)
918
+ if ($event.button === 1) {
919
+ //$event.preventDefault();
920
+ contextMenu.closeMenu();
921
+ // Converts the route into a string that can be used
922
+ // with the window.open() function
923
+ const url = this.router.serializeUrl(queryParamName && queryParamValue ?
924
+ this.router.createUrlTree([baseUrl], { queryParams: { [queryParamName]: item[queryParamValue] } })
925
+ : this.router.createUrlTree([baseUrl]));
926
+ window.open(url, '_blank');
927
+ }
928
+ };
929
+ }
930
+ // Action в таблице: При щелчке ПКМ открыть в новой вкладке.
931
+ onActionMiddleButton(baseUrl, queryParamName, queryParamValue) {
932
+ return ($event, item) => {
933
+ // Нажата средняя кнопка (в новой вкладке).
934
+ // 1 - Auxiliary button pressed (usually the middle button)
935
+ if ($event.button === 1) {
936
+ //$event.preventDefault();
937
+ // Converts the route into a string that can be used
938
+ // with the window.open() function
939
+ const url = this.router.serializeUrl(queryParamName && queryParamValue ?
940
+ this.router.createUrlTree([baseUrl], { queryParams: { [queryParamName]: item[queryParamValue] } })
941
+ : this.router.createUrlTree([baseUrl]));
942
+ window.open(url, '_blank');
943
+ }
944
+ };
945
+ }
946
+ dateToString(date) {
947
+ return date ? (new Date(date)).toLocaleString('ru-RU', { timeZone: 'Europe/Samara' }) : null; // MSK+01
948
+ }
949
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: BasePageClass, deps: [], target: i0.ɵɵFactoryTarget.Directive });
950
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.0", type: BasePageClass, isStandalone: true, ngImport: i0 });
951
+ }
952
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: BasePageClass, decorators: [{
953
+ type: Directive
954
+ }], ctorParameters: () => [] });
955
+
956
+ class BaseServiceClass {
957
+ countRoute = 'count';
958
+ pageIndexParam = 'page';
959
+ pageSizeParam = 'limit';
960
+ sortColumnParam = 'column';
961
+ directionParam = 'direction';
962
+ http = inject(HttpClient);
963
+ getObjects() {
964
+ return this.http.get(this.baseRoute)
965
+ .pipe(map(data => data.map(item => new this.entityType(item).deserialize(item))));
966
+ }
967
+ getObject(id) {
968
+ return this.http.get(this.baseRoute + id)
969
+ .pipe(map(data => new this.entityType(data).deserialize(data)));
970
+ }
971
+ getCount() {
972
+ return this.http.get(this.baseRoute + this.countRoute);
973
+ }
974
+ getObjectsByPaging(pageIndex, pageSize, sortColumn, direction) {
975
+ const params = this.getParams(pageIndex, pageSize, sortColumn, direction);
976
+ return this.http.get(this.baseRoute, { params })
977
+ .pipe(map(data => data.map(item => new this.entityType(item).deserialize(item))));
978
+ }
979
+ newObject(entity) {
980
+ return this.http.post(this.baseRoute, entity);
981
+ }
982
+ editObject(entity) {
983
+ return this.http.put(this.baseRoute + entity.id, entity);
984
+ }
985
+ deleteObject(entity) {
986
+ return this.http.delete(this.baseRoute + entity.id);
987
+ }
988
+ getParams(pageIndex, pageSize, sortColumn, direction) {
989
+ let params = new HttpParams();
990
+ if (pageIndex + 1)
991
+ // переход от индекса к номеру страницы
992
+ params = params.append(this.pageIndexParam, pageIndex + 1);
993
+ if (pageSize)
994
+ params = params.append(this.pageSizeParam, pageSize);
995
+ if (sortColumn)
996
+ params = params.append(this.sortColumnParam, sortColumn);
997
+ if (direction)
998
+ params = params.append(this.directionParam, direction);
999
+ return params;
1000
+ }
1001
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: BaseServiceClass, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1002
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: BaseServiceClass, providedIn: 'root' });
1003
+ }
1004
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: BaseServiceClass, decorators: [{
1005
+ type: Injectable,
1006
+ args: [{
1007
+ providedIn: 'root'
1008
+ }]
1009
+ }] });
1010
+
1011
+ class SafePipe {
1012
+ sanitizer = inject(DomSanitizer);
1013
+ transform(url) {
1014
+ return this.sanitizer.bypassSecurityTrustResourceUrl(url);
1015
+ }
1016
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: SafePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
1017
+ static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.0", ngImport: i0, type: SafePipe, isStandalone: true, name: "safe" });
1018
+ }
1019
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: SafePipe, decorators: [{
1020
+ type: Pipe,
1021
+ args: [{
1022
+ name: 'safe'
1023
+ }]
1024
+ }] });
1025
+
1026
+ class TimePipe {
1027
+ transform(value) {
1028
+ // const hour = Math.abs(value) >= 60 ? Math.round(value / 60) + 'ч.' : '';
1029
+ // const minute = ' ' + Math.abs(value % 60) + 'м.';
1030
+ // return value === 0 ? '0' : hour + ' ' + minute;
1031
+ const hour = Math.abs(value) >= 60 ? Math.floor(Math.abs(value) / 60).toString().padStart(2, '0') : '00';
1032
+ const minute = Math.abs(value % 60).toString().padStart(2, '0');
1033
+ const time = hour + ':' + minute;
1034
+ return value < 0 ? '-' + time : time;
1035
+ }
1036
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TimePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
1037
+ static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.0", ngImport: i0, type: TimePipe, isStandalone: true, name: "time" });
1038
+ }
1039
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TimePipe, decorators: [{
1040
+ type: Pipe,
1041
+ args: [{
1042
+ name: 'time'
1043
+ }]
1044
+ }] });
1045
+
1046
+ class TruncatePipe {
1047
+ // Usage:
1048
+ // {{ str | truncate:[20] }} // or
1049
+ // {{ str | truncate:[20, '...'] }} // or|
1050
+ transform(value, args) {
1051
+ const limit = args.length > 0 ? parseInt(args[0], 10) : 20;
1052
+ const trail = args.length > 1 ? args[1] : '...';
1053
+ return value.length > limit ? value.substring(0, limit) + trail : value;
1054
+ }
1055
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TruncatePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
1056
+ static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.0", ngImport: i0, type: TruncatePipe, isStandalone: true, name: "truncate" });
1057
+ }
1058
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TruncatePipe, decorators: [{
1059
+ type: Pipe,
1060
+ args: [{
1061
+ name: 'truncate'
1062
+ }]
1063
+ }] });
1064
+
1065
+ class NavBarComponent extends BaseNavBarMenuClass {
1066
+ /** Видимость панели, когда loggedIn === false. */
1067
+ visibleOnLogout = input(false, ...(ngDevMode ? [{ debugName: "visibleOnLogout" }] : []));
1068
+ /** Видимость аватара. */
1069
+ visibleAvatar = input(true, ...(ngDevMode ? [{ debugName: "visibleAvatar" }] : []));
1070
+ /** Видимость кнопки "Выйти". */
1071
+ visibleLogoutBtn = input(true, ...(ngDevMode ? [{ debugName: "visibleLogoutBtn" }] : []));
1072
+ /** Признак, что пользователь авторизован. */
1073
+ loggedIn = input(false, ...(ngDevMode ? [{ debugName: "loggedIn" }] : []));
1074
+ /** ФИО пользователя. */
1075
+ fioUser = input('', ...(ngDevMode ? [{ debugName: "fioUser" }] : []));
1076
+ /** Всплывающая подсказка о пользователе. */
1077
+ userTooltip = input('', ...(ngDevMode ? [{ debugName: "userTooltip" }] : []));
1078
+ /** URL аватара */
1079
+ avatarURL = input('', ...(ngDevMode ? [{ debugName: "avatarURL" }] : []));
1080
+ /** Нажата кнопка "Выйти". */
1081
+ logout = output();
1082
+ dialog = inject(MatDialog);
1083
+ constructor() {
1084
+ super();
1085
+ }
1086
+ onLogout() {
1087
+ this.logout.emit(this.router.url);
1088
+ }
1089
+ openDialog() {
1090
+ const dialogRef = this.dialog.open(DialogComponent, {
1091
+ width: '400px',
1092
+ data: {
1093
+ id: 'logout',
1094
+ title: 'Подтверждение',
1095
+ message: 'Вы хотите выйти?',
1096
+ btnNoTitle: 'Отмена',
1097
+ btnYesTitle: 'Выйти'
1098
+ }
1099
+ });
1100
+ const subs = dialogRef.afterClosed().subscribe((id) => {
1101
+ if (id) {
1102
+ this.onLogout();
1103
+ }
1104
+ });
1105
+ this.subscription.add(subs);
1106
+ }
1107
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NavBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1108
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: NavBarComponent, isStandalone: true, selector: "ngx-uik-navbar", inputs: { visibleOnLogout: { classPropertyName: "visibleOnLogout", publicName: "visibleOnLogout", isSignal: true, isRequired: false, transformFunction: null }, visibleAvatar: { classPropertyName: "visibleAvatar", publicName: "visibleAvatar", isSignal: true, isRequired: false, transformFunction: null }, visibleLogoutBtn: { classPropertyName: "visibleLogoutBtn", publicName: "visibleLogoutBtn", isSignal: true, isRequired: false, transformFunction: null }, loggedIn: { classPropertyName: "loggedIn", publicName: "loggedIn", isSignal: true, isRequired: false, transformFunction: null }, fioUser: { classPropertyName: "fioUser", publicName: "fioUser", isSignal: true, isRequired: false, transformFunction: null }, userTooltip: { classPropertyName: "userTooltip", publicName: "userTooltip", isSignal: true, isRequired: false, transformFunction: null }, avatarURL: { classPropertyName: "avatarURL", publicName: "avatarURL", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { logout: "logout" }, usesInheritance: true, ngImport: i0, template: "@if (visibleOnLogout() || loggedIn()) {\r\n <nav class=\"ngx-uik-navbar-header\">\r\n \r\n <ng-content></ng-content>\r\n\r\n <div class=\"flex-spacer\"></div>\r\n \r\n @if (visibleAvatar() && (loggedIn() === false || !avatarURL)) {\r\n <mat-icon [matTooltip]=\"userTooltip()\">account_circle</mat-icon>\r\n }\r\n @if (visibleAvatar() && loggedIn() && avatarURL()) {\r\n <img\r\n class=\"user-photo\"\r\n [src]=\"avatarURL() | safe\"\r\n loading=\"lazy\"\r\n [alt]=\"fioUser()\"\r\n [matTooltip]=\"userTooltip()\">\r\n }\r\n\r\n <span class = \"user-name\" [matTooltip]=\"userTooltip()\">\r\n {{ fioUser() }}\r\n </span>\r\n\r\n @if (visibleLogoutBtn()) {\r\n <a mat-button class=\"pm-button\" (click)=\"openDialog()\">\u0412\u044B\u0439\u0442\u0438 <mat-icon>logout</mat-icon></a>\r\n }\r\n </nav>\r\n}", styles: [".ngx-uik-navbar-header{display:flex;flex-wrap:wrap;align-items:center;padding:8px 16px}.flex-spacer{flex-grow:1}.user-name{margin-left:8px;line-height:1rem;white-space:normal}.user-photo{border-radius:50%;width:32px;height:32px;margin-right:10px}.mat-mdc-button{color:#fff!important;padding-left:16px!important;padding-right:16px!important}.mdc-button{letter-spacing:normal}\n"], dependencies: [{ kind: "component", type: MatAnchor, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "pipe", type: SafePipe, name: "safe" }] });
1109
+ }
1110
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NavBarComponent, decorators: [{
1111
+ type: Component,
1112
+ args: [{ selector: 'ngx-uik-navbar', imports: [MatAnchor, MatIcon, MatTooltip, SafePipe], template: "@if (visibleOnLogout() || loggedIn()) {\r\n <nav class=\"ngx-uik-navbar-header\">\r\n \r\n <ng-content></ng-content>\r\n\r\n <div class=\"flex-spacer\"></div>\r\n \r\n @if (visibleAvatar() && (loggedIn() === false || !avatarURL)) {\r\n <mat-icon [matTooltip]=\"userTooltip()\">account_circle</mat-icon>\r\n }\r\n @if (visibleAvatar() && loggedIn() && avatarURL()) {\r\n <img\r\n class=\"user-photo\"\r\n [src]=\"avatarURL() | safe\"\r\n loading=\"lazy\"\r\n [alt]=\"fioUser()\"\r\n [matTooltip]=\"userTooltip()\">\r\n }\r\n\r\n <span class = \"user-name\" [matTooltip]=\"userTooltip()\">\r\n {{ fioUser() }}\r\n </span>\r\n\r\n @if (visibleLogoutBtn()) {\r\n <a mat-button class=\"pm-button\" (click)=\"openDialog()\">\u0412\u044B\u0439\u0442\u0438 <mat-icon>logout</mat-icon></a>\r\n }\r\n </nav>\r\n}", styles: [".ngx-uik-navbar-header{display:flex;flex-wrap:wrap;align-items:center;padding:8px 16px}.flex-spacer{flex-grow:1}.user-name{margin-left:8px;line-height:1rem;white-space:normal}.user-photo{border-radius:50%;width:32px;height:32px;margin-right:10px}.mat-mdc-button{color:#fff!important;padding-left:16px!important;padding-right:16px!important}.mdc-button{letter-spacing:normal}\n"] }]
1113
+ }], ctorParameters: () => [], propDecorators: { visibleOnLogout: [{ type: i0.Input, args: [{ isSignal: true, alias: "visibleOnLogout", required: false }] }], visibleAvatar: [{ type: i0.Input, args: [{ isSignal: true, alias: "visibleAvatar", required: false }] }], visibleLogoutBtn: [{ type: i0.Input, args: [{ isSignal: true, alias: "visibleLogoutBtn", required: false }] }], loggedIn: [{ type: i0.Input, args: [{ isSignal: true, alias: "loggedIn", required: false }] }], fioUser: [{ type: i0.Input, args: [{ isSignal: true, alias: "fioUser", required: false }] }], userTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "userTooltip", required: false }] }], avatarURL: [{ type: i0.Input, args: [{ isSignal: true, alias: "avatarURL", required: false }] }], logout: [{ type: i0.Output, args: ["logout"] }] } });
1114
+
1115
+ class NotFoundComponent {
1116
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NotFoundComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1117
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.0", type: NotFoundComponent, isStandalone: true, selector: "ngx-uik-not-found", ngImport: i0, template: "<div class=\"center\">\r\n <h3 class=\"mat-display-1\">\u0421\u0442\u0440\u0430\u043D\u0438\u0446\u0430 \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u0430</h3>\r\n</div>\r\n", styles: [".center{display:flex;justify-content:center;margin:3rem}\n"] });
1118
+ }
1119
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NotFoundComponent, decorators: [{
1120
+ type: Component,
1121
+ args: [{ selector: 'ngx-uik-not-found', standalone: true, template: "<div class=\"center\">\r\n <h3 class=\"mat-display-1\">\u0421\u0442\u0440\u0430\u043D\u0438\u0446\u0430 \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u0430</h3>\r\n</div>\r\n", styles: [".center{display:flex;justify-content:center;margin:3rem}\n"] }]
1122
+ }] });
1123
+
1124
+ class ProgressSpinnerComponent {
1125
+ cdRef = inject(ChangeDetectorRef);
1126
+ ngAfterViewInit() {
1127
+ this.cdRef.detectChanges();
1128
+ }
1129
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: ProgressSpinnerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1130
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.0", type: ProgressSpinnerComponent, isStandalone: true, selector: "ngx-uik-loader", ngImport: i0, template: `
1131
+ <div class="loading-indicator" mat-dialog-content>
1132
+ <mat-progress-spinner mode="indeterminate">
1133
+ </mat-progress-spinner>
1134
+ </div>
1135
+ `, isInline: true, styles: [".loading-indicator{position:fixed;z-index:999;height:2em;width:2em;overflow:initial;margin:auto;inset:0}.loading-indicator:before{content:\"\";display:block;position:fixed;top:0;left:0;width:100%;height:100%;background-color:#0000004d}\n"], dependencies: [{ kind: "component", type: MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1136
+ }
1137
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: ProgressSpinnerComponent, decorators: [{
1138
+ type: Component,
1139
+ args: [{ selector: 'ngx-uik-loader', template: `
1140
+ <div class="loading-indicator" mat-dialog-content>
1141
+ <mat-progress-spinner mode="indeterminate">
1142
+ </mat-progress-spinner>
1143
+ </div>
1144
+ `, changeDetection: ChangeDetectionStrategy.OnPush, imports: [MatProgressSpinner], styles: [".loading-indicator{position:fixed;z-index:999;height:2em;width:2em;overflow:initial;margin:auto;inset:0}.loading-indicator:before{content:\"\";display:block;position:fixed;top:0;left:0;width:100%;height:100%;background-color:#0000004d}\n"] }]
1145
+ }] });
1146
+
1147
+ class BaseSelectAutocompleteWithVsComponent {
1148
+ // https://stackblitz.com/edit/autocomplete-with-virtual-scroll-dc9u2g
1149
+ // Все элементы
1150
+ items = input([], ...(ngDevMode ? [{ debugName: "items" }] : []));
1151
+ // Выбранный элемент (входной параметр)
1152
+ selectedItemInput = input(undefined, ...(ngDevMode ? [{ debugName: "selectedItemInput" }] : []));
1153
+ // Заголовок
1154
+ title = input('', ...(ngDevMode ? [{ debugName: "title" }] : []));
1155
+ // Видимость
1156
+ isVisible = input(true, ...(ngDevMode ? [{ debugName: "isVisible" }] : []));
1157
+ // Обязательность
1158
+ isRequired = input(false, ...(ngDevMode ? [{ debugName: "isRequired" }] : []));
1159
+ // Доступность
1160
+ isDisabled = input(false, ...(ngDevMode ? [{ debugName: "isDisabled" }] : []));
1161
+ // Доступность
1162
+ width = input('200', ...(ngDevMode ? [{ debugName: "width" }] : []));
1163
+ // Выбранный элемент
1164
+ selectedItem = linkedSignal(() => this.selectedItemInput(), ...(ngDevMode ? [{ debugName: "selectedItem" }] : []));
1165
+ // Событие изменения выбранного элемента
1166
+ selectedItemChange = output();
1167
+ height = '200px';
1168
+ // input элемент
1169
+ inputCtrl = new FormControl();
1170
+ // отфильтрованные (отображаемые) элементы
1171
+ filteredItems = [];
1172
+ subscription = new Subscription();
1173
+ constructor() {
1174
+ effect(() => {
1175
+ console.log('ITEMS =', this.items());
1176
+ //this.filteredItems = this.items();
1177
+ console.log('selectedItem =', this.selectedItemInput());
1178
+ if (this.items().length > 0) {
1179
+ console.log('filteredItems SET');
1180
+ this.setFileredItems(this.items());
1181
+ this.inputCtrl.setValue(this.selectedItemInput());
1182
+ }
1183
+ });
1184
+ }
1185
+ ngOnInit() {
1186
+ // Listen for changes to the input
1187
+ const subs = this.inputCtrl.valueChanges
1188
+ .pipe(startWith$1(''),
1189
+ // eslint-disable-next-line no-magic-numbers
1190
+ debounceTime(500), distinctUntilChanged(),
1191
+ // Note: If the option value is bound to object, after selecting the option
1192
+ // Note: the value will change from string to {}. We want to perform search
1193
+ // Note: only when the type is string (no match)
1194
+ //filter(q => typeof q === 'string'),
1195
+ //tap((v) => console.log('v=', v)),
1196
+ map((value) => {
1197
+ // Filter the options
1198
+ console.log('typeof value =', typeof value);
1199
+ if (typeof value === 'undefined') {
1200
+ this.setFileredItems(this.items());
1201
+ }
1202
+ else {
1203
+ if (typeof value !== 'object') {
1204
+ console.log('v1=', value);
1205
+ this.setFileredItems(this.items()
1206
+ .filter(option => option.viewValue.toLowerCase().includes(value.toLowerCase())));
1207
+ }
1208
+ else {
1209
+ // typeof value === 'object'
1210
+ console.log('v2=', value);
1211
+ if (value) {
1212
+ // this.predmet = value;
1213
+ this.setFileredItems(this.items()
1214
+ .filter((option) => option.viewValue.toLowerCase().includes(value.viewValue.toLowerCase())));
1215
+ console.log('v3=', value);
1216
+ }
1217
+ else {
1218
+ this.setFileredItems(this.items());
1219
+ console.log('v4=', value);
1220
+ }
1221
+ }
1222
+ }
1223
+ }))
1224
+ .subscribe();
1225
+ this.subscription.add(subs);
1226
+ if (this.isDisabled()) {
1227
+ this.inputCtrl.disable();
1228
+ }
1229
+ else {
1230
+ this.inputCtrl.enable();
1231
+ }
1232
+ }
1233
+ ngOnDestroy() {
1234
+ if (this.subscription)
1235
+ this.subscription.unsubscribe();
1236
+ }
1237
+ onSelectedItemChange(item) {
1238
+ console.log("onSelectedItemChange, item=", item);
1239
+ this.selectedItem.set(item);
1240
+ this.selectedItemChange.emit(item);
1241
+ }
1242
+ onClearClick($event) {
1243
+ $event.stopPropagation();
1244
+ this.inputCtrl.setValue('');
1245
+ }
1246
+ displayWithFn(lookup) {
1247
+ return lookup ? lookup.viewValue : null;
1248
+ }
1249
+ setFileredItems(items) {
1250
+ this.filteredItems = items;
1251
+ // Recompute how big the viewport should be.
1252
+ // eslint-disable-next-line no-magic-numbers
1253
+ if (items.length < 4) {
1254
+ // eslint-disable-next-line no-magic-numbers
1255
+ this.height = items.length * 50 + 'px';
1256
+ }
1257
+ else {
1258
+ this.height = '200px';
1259
+ }
1260
+ console.log('update filteredItems =', this.filteredItems);
1261
+ }
1262
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: BaseSelectAutocompleteWithVsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1263
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: BaseSelectAutocompleteWithVsComponent, isStandalone: true, selector: "ngx-uik-select-autocomplete-with-vs", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, selectedItemInput: { classPropertyName: "selectedItemInput", publicName: "selectedItemInput", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, isVisible: { classPropertyName: "isVisible", publicName: "isVisible", isSignal: true, isRequired: false, transformFunction: null }, isRequired: { classPropertyName: "isRequired", publicName: "isRequired", isSignal: true, isRequired: false, transformFunction: null }, isDisabled: { classPropertyName: "isDisabled", publicName: "isDisabled", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedItemChange: "selectedItemChange" }, ngImport: i0, template: "@if (isVisible()) {\r\n <mat-form-field [style.width.px]=\"width()\">\r\n <mat-label>{{ title() }}</mat-label>\r\n <input type=\"text\"\r\n [placeholder]=title()\r\n aria-label=\"Number\"\r\n matInput\r\n (ngModelChange)=\"onSelectedItemChange($event)\"\r\n [formControl]=\"inputCtrl\"\r\n [matAutocomplete]=\"auto\"\r\n [required]=\"isRequired() ? 'required' : ''\"\r\n >\r\n @if (!isDisabled && selectedItem()) {\r\n <button mat-button matSuffix mat-icon-button aria-label=\"Clear\" (click)=\"onClearClick($event)\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n }\r\n <mat-autocomplete #auto=\"matAutocomplete\" [displayWith]=\"displayWithFn\" showPanel=\"true\">\r\n <cdk-virtual-scroll-viewport class=\"autocomplete-test-viewport\" [style.height]=\"height\" itemSize=\"25\">\r\n <mat-option *cdkVirtualFor=\"let option of filteredItems\" [value]=\"option\" class=\"autocomplete-item\">\r\n {{option.viewValue}}\r\n </mat-option>\r\n </cdk-virtual-scroll-viewport>\r\n </mat-autocomplete>\r\n @if (inputCtrl.invalid) {\r\n <mat-error>\u0412\u0432\u0435\u0434\u0438\u0442\u0435 {{title()}}</mat-error>\r\n }\r\n @if (!inputCtrl.value) {\r\n <mat-hint>\u041D\u0430\u0447\u043D\u0438\u0442\u0435 \u0432\u0432\u043E\u0434\u0438\u0442\u044C ...</mat-hint>\r\n }\r\n </mat-form-field>\r\n}", styles: ["mat-form-field{margin-right:12px}.autocomplete-item{height:50px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.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: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatAutocompleteModule }, { kind: "component", type: i2.MatAutocomplete, selector: "mat-autocomplete", inputs: ["aria-label", "aria-labelledby", "displayWith", "autoActiveFirstOption", "autoSelectActiveOption", "requireSelection", "panelWidth", "disableRipple", "class", "hideSingleSelectionIndicator"], outputs: ["optionSelected", "opened", "closed", "optionActivated"], exportAs: ["matAutocomplete"] }, { kind: "component", type: i2.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: i2.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", inputs: ["matAutocomplete", "matAutocompletePosition", "matAutocompleteConnectedTo", "autocomplete", "matAutocompleteDisabled"], exportAs: ["matAutocompleteTrigger"] }, { kind: "directive", type: MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i3$1.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i3$1.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i3$1.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "directive", type: MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "directive", type: MatLabel, selector: "mat-label" }] });
1264
+ }
1265
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: BaseSelectAutocompleteWithVsComponent, decorators: [{
1266
+ type: Component,
1267
+ args: [{ selector: 'ngx-uik-select-autocomplete-with-vs', imports: [FormsModule, ReactiveFormsModule, MatAutocompleteModule, MatHint, MatError, MatOption, MatIcon,
1268
+ MatFormField, ScrollingModule, MatInput, MatLabel], template: "@if (isVisible()) {\r\n <mat-form-field [style.width.px]=\"width()\">\r\n <mat-label>{{ title() }}</mat-label>\r\n <input type=\"text\"\r\n [placeholder]=title()\r\n aria-label=\"Number\"\r\n matInput\r\n (ngModelChange)=\"onSelectedItemChange($event)\"\r\n [formControl]=\"inputCtrl\"\r\n [matAutocomplete]=\"auto\"\r\n [required]=\"isRequired() ? 'required' : ''\"\r\n >\r\n @if (!isDisabled && selectedItem()) {\r\n <button mat-button matSuffix mat-icon-button aria-label=\"Clear\" (click)=\"onClearClick($event)\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n }\r\n <mat-autocomplete #auto=\"matAutocomplete\" [displayWith]=\"displayWithFn\" showPanel=\"true\">\r\n <cdk-virtual-scroll-viewport class=\"autocomplete-test-viewport\" [style.height]=\"height\" itemSize=\"25\">\r\n <mat-option *cdkVirtualFor=\"let option of filteredItems\" [value]=\"option\" class=\"autocomplete-item\">\r\n {{option.viewValue}}\r\n </mat-option>\r\n </cdk-virtual-scroll-viewport>\r\n </mat-autocomplete>\r\n @if (inputCtrl.invalid) {\r\n <mat-error>\u0412\u0432\u0435\u0434\u0438\u0442\u0435 {{title()}}</mat-error>\r\n }\r\n @if (!inputCtrl.value) {\r\n <mat-hint>\u041D\u0430\u0447\u043D\u0438\u0442\u0435 \u0432\u0432\u043E\u0434\u0438\u0442\u044C ...</mat-hint>\r\n }\r\n </mat-form-field>\r\n}", styles: ["mat-form-field{margin-right:12px}.autocomplete-item{height:50px}\n"] }]
1269
+ }], ctorParameters: () => [], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], selectedItemInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedItemInput", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], isVisible: [{ type: i0.Input, args: [{ isSignal: true, alias: "isVisible", required: false }] }], isRequired: [{ type: i0.Input, args: [{ isSignal: true, alias: "isRequired", required: false }] }], isDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "isDisabled", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], selectedItemChange: [{ type: i0.Output, args: ["selectedItemChange"] }] } });
1270
+
1271
+ class BaseSelectWithGroupComponent {
1272
+ // Все группы
1273
+ groups = input([], ...(ngDevMode ? [{ debugName: "groups" }] : []));
1274
+ // Выбранные элементы, ключи (BaseSelectItem.value)
1275
+ selectedItems = input([], ...(ngDevMode ? [{ debugName: "selectedItems" }] : []));
1276
+ // Заголовок
1277
+ title = input('', ...(ngDevMode ? [{ debugName: "title" }] : []));
1278
+ // Событие изменения выбранных элементов
1279
+ selectedItemsChange = output();
1280
+ separatorKeysCodes = [ENTER, COMMA];
1281
+ control = new FormControl([]);
1282
+ constructor() {
1283
+ effect(() => {
1284
+ if (this.groups().length > 0) {
1285
+ this.control.setValue(this.selectedItems().map(i => Number(i)));
1286
+ }
1287
+ });
1288
+ }
1289
+ selectionChange($event) {
1290
+ this.selectedItemsChange.emit($event.value.map((i) => i.toString()));
1291
+ }
1292
+ onClearClick($event) {
1293
+ $event.stopPropagation();
1294
+ // this.control.setValue('');
1295
+ this.selectedItemsChange.emit([]);
1296
+ }
1297
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: BaseSelectWithGroupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1298
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: BaseSelectWithGroupComponent, isStandalone: true, selector: "ngx-uik-select-with-group", inputs: { groups: { classPropertyName: "groups", publicName: "groups", isSignal: true, isRequired: false, transformFunction: null }, selectedItems: { classPropertyName: "selectedItems", publicName: "selectedItems", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedItemsChange: "selectedItemsChange" }, ngImport: i0, template: "<mat-form-field class=\"select-with-group\" appearance=\"fill\">\r\n <mat-label>{{ title() }}</mat-label>\r\n <mat-select [formControl]=\"control\" (selectionChange)=\"selectionChange($event)\" multiple>\r\n @for (group of groups(); track group) {\r\n <mat-optgroup [label]=\"group.name\">\r\n @for (item of group.items; track item) {\r\n <mat-option [value]=\"item.value\" >\r\n {{item.viewValue}}\r\n </mat-option>\r\n }\r\n </mat-optgroup>\r\n }\r\n\r\n </mat-select>\r\n @if (control.value && control.value!.length > 0) {\r\n <button matSuffix mat-icon-button aria-label=\"Clear\" (click)=\"onClearClick($event)\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n }\r\n</mat-form-field>\r\n", styles: [".select-with-group{width:100%}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: MatOption$1, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "component", type: MatOptgroup, selector: "mat-optgroup", inputs: ["label", "disabled"], exportAs: ["matOptgroup"] }, { kind: "component", type: MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: MatFormField$1, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: MatLabel$1, selector: "mat-label" }] });
1299
+ }
1300
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: BaseSelectWithGroupComponent, decorators: [{
1301
+ type: Component,
1302
+ args: [{ selector: 'ngx-uik-select-with-group', imports: [FormsModule, ReactiveFormsModule, MatIcon, MatOption$1, MatOptgroup, MatSelect, MatFormField$1, MatLabel$1], template: "<mat-form-field class=\"select-with-group\" appearance=\"fill\">\r\n <mat-label>{{ title() }}</mat-label>\r\n <mat-select [formControl]=\"control\" (selectionChange)=\"selectionChange($event)\" multiple>\r\n @for (group of groups(); track group) {\r\n <mat-optgroup [label]=\"group.name\">\r\n @for (item of group.items; track item) {\r\n <mat-option [value]=\"item.value\" >\r\n {{item.viewValue}}\r\n </mat-option>\r\n }\r\n </mat-optgroup>\r\n }\r\n\r\n </mat-select>\r\n @if (control.value && control.value!.length > 0) {\r\n <button matSuffix mat-icon-button aria-label=\"Clear\" (click)=\"onClearClick($event)\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n }\r\n</mat-form-field>\r\n", styles: [".select-with-group{width:100%}\n"] }]
1303
+ }], ctorParameters: () => [], propDecorators: { groups: [{ type: i0.Input, args: [{ isSignal: true, alias: "groups", required: false }] }], selectedItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedItems", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], selectedItemsChange: [{ type: i0.Output, args: ["selectedItemsChange"] }] } });
1304
+
1305
+ class TableComponent {
1306
+ /** Отображаемые данные. */
1307
+ data = input([], ...(ngDevMode ? [{ debugName: "data" }] : []));
1308
+ /** Количество записей. */
1309
+ length = input(0, ...(ngDevMode ? [{ debugName: "length" }] : []));
1310
+ /** Настройки колонок. */
1311
+ columnOptions = input([], ...(ngDevMode ? [{ debugName: "columnOptions" }] : []));
1312
+ /** Состояние сортировки, пагинации. */
1313
+ tableState = input.required(...(ngDevMode ? [{ debugName: "tableState" }] : []));
1314
+ /** Разрешен выбор нескольких строк. */
1315
+ allowMultiSelect = input(false, ...(ngDevMode ? [{ debugName: "allowMultiSelect" }] : []));
1316
+ /** Список элементов контекстного меню. */
1317
+ opt = input([], ...(ngDevMode ? [{ debugName: "opt" }] : []));
1318
+ /** Отправка события rowDoubleClicked (при двойном щелчке мышью) отключена. */
1319
+ rowDblClickedDisable = input(false, ...(ngDevMode ? [{ debugName: "rowDblClickedDisable" }] : []));
1320
+ /** Отображать строку с итогом. */
1321
+ footer = input(false, ...(ngDevMode ? [{ debugName: "footer" }] : []));
1322
+ /** Изменение страницы. */
1323
+ pageStateChange = output();
1324
+ /** Изменение сортировки. */
1325
+ sortStateChange = output();
1326
+ /** Изменение выбранных записей. */
1327
+ selectionChange = output();
1328
+ /** Двойной щелчек ЛКМ*/
1329
+ rowDoubleClicked = output();
1330
+ sort = viewChild(MatSort, ...(ngDevMode ? [{ debugName: "sort" }] : []));
1331
+ paginator = viewChild(MatPaginator, ...(ngDevMode ? [{ debugName: "paginator" }] : []));
1332
+ contextMenu = viewChild(MatMenuTrigger, ...(ngDevMode ? [{ debugName: "contextMenu" }] : []));
1333
+ pageState = linkedSignal(() => {
1334
+ return { pageIndex: this.tableState().pageIndex, pageSize: this.tableState().pageSize };
1335
+ }, ...(ngDevMode ? [{ debugName: "pageState" }] : []));
1336
+ sortState = linkedSignal(() => {
1337
+ return { sortActive: this.tableState().sortActive, sortDirection: this.tableState().sortDirection };
1338
+ }, ...(ngDevMode ? [{ debugName: "sortState" }] : []));
1339
+ /** Выбранная строка, для которого будет показываться меню при нажатии правой кнопки мыши. */
1340
+ itemForMenu;
1341
+ /** Позиция в которой отображается контекстное меню. */
1342
+ contextMenuPosition = { x: '0px', y: '0px' };
1343
+ // eslint-disable-next-line no-magic-numbers
1344
+ defaultPageIndex = 0;
1345
+ // eslint-disable-next-line no-magic-numbers
1346
+ defaultPageSize = 10;
1347
+ /** Источник данных для отображения. */
1348
+ dataSource = new MatTableDataSource();
1349
+ /** Выбранные записи. */
1350
+ selection = new SelectionModel();
1351
+ /** Список отображаемых колонок (формируется из @columnOptions). */
1352
+ displayedColumns;
1353
+ subscription = new Subscription();
1354
+ constructor() {
1355
+ effect(() => {
1356
+ this.dataSource.data = this.data();
1357
+ // сохранить выделенные строки, если они все еще есть в данных
1358
+ const selected = this.selection.selected;
1359
+ this.selection.clear();
1360
+ this.data().filter(v => selected.map(s => JSON.stringify(s)).includes(JSON.stringify(v))).map(d => {
1361
+ this.selection.select(d);
1362
+ });
1363
+ });
1364
+ }
1365
+ ngOnInit() {
1366
+ this.displayedColumns = ['select'].concat(this.columnOptions()?.filter(c => !c.hide).map((item) => item.name) || []);
1367
+ // пересоздаем, т.к. параметр allowMultiSelect появляется только сейчас
1368
+ this.selection = new SelectionModel(this.allowMultiSelect());
1369
+ }
1370
+ ngOnDestroy() {
1371
+ if (this.subscription)
1372
+ this.subscription.unsubscribe();
1373
+ }
1374
+ ngAfterViewInit() {
1375
+ // подписи элементов управления пагинатора (MatPaginatorIntl)
1376
+ const paginator = this.paginator();
1377
+ if (paginator) {
1378
+ paginator._intl.itemsPerPageLabel = 'Записей на странице';
1379
+ paginator._intl.firstPageLabel = 'Первая страница';
1380
+ paginator._intl.previousPageLabel = 'Предыдущая страница';
1381
+ paginator._intl.nextPageLabel = 'Следующая страница';
1382
+ paginator._intl.lastPageLabel = 'Последняя страница';
1383
+ // изменение пагинации
1384
+ const subs = paginator.page.subscribe(page => {
1385
+ const pageState = {
1386
+ pageIndex: page.pageIndex,
1387
+ pageSize: page.pageSize
1388
+ };
1389
+ this.pageState.set(pageState);
1390
+ this.pageStateChange.emit(pageState);
1391
+ });
1392
+ this.subscription.add(subs);
1393
+ }
1394
+ // изменение сортировки
1395
+ const sortValue = this.sort();
1396
+ if (sortValue) {
1397
+ const subs = sortValue.sortChange
1398
+ .subscribe(sort => {
1399
+ const sortState = {
1400
+ sortActive: sort.active,
1401
+ sortDirection: sort.direction
1402
+ };
1403
+ this.sortState.set(sortState);
1404
+ this.sortStateChange.emit(sortState);
1405
+ });
1406
+ this.subscription.add(subs);
1407
+ }
1408
+ // изменение выбранных записей
1409
+ if (this.selection) {
1410
+ const subs = this.selection.changed.subscribe(change => {
1411
+ this.selectionChange.emit(change.source.selected);
1412
+ });
1413
+ this.subscription.add(subs);
1414
+ }
1415
+ }
1416
+ /** Whether the number of selected elements matches the total number of rows. */
1417
+ isAllSelected() {
1418
+ const numSelected = this.selection.selected.length;
1419
+ const numRows = this.dataSource.data.length;
1420
+ return numSelected === numRows;
1421
+ }
1422
+ /** Selects all rows if they are not all selected; otherwise clear selection. */
1423
+ masterToggle() {
1424
+ console.log(this.selection.isMultipleSelection());
1425
+ if (this.isAllSelected()) {
1426
+ this.selection.clear();
1427
+ }
1428
+ else {
1429
+ this.dataSource.data.forEach(row => this.selection.select(row));
1430
+ }
1431
+ }
1432
+ /** При щелчке по строке. */
1433
+ onRowClicked(row) {
1434
+ // выделение строки при щелчке по строке
1435
+ if (this.selection.isSelected(row)) {
1436
+ this.selection.deselect(row);
1437
+ }
1438
+ else {
1439
+ this.selection.select(row);
1440
+ }
1441
+ }
1442
+ /** При двойном щелчке по строке. */
1443
+ onRowDblClicked(row) {
1444
+ // выделение строки при двойном щелчке по строке
1445
+ this.selection.clear();
1446
+ this.selection.select(row);
1447
+ if (!this.rowDblClickedDisable())
1448
+ this.rowDoubleClicked.emit(row);
1449
+ }
1450
+ /** При вызове контекстного меню. */
1451
+ onContextMenu(event, itemForMenu) {
1452
+ if (this.opt() && this.opt().length === 0) {
1453
+ // если нет пунктов меню, то не показываем меню
1454
+ return;
1455
+ }
1456
+ event.preventDefault();
1457
+ this.itemForMenu = itemForMenu;
1458
+ this.contextMenuPosition.x = event.clientX + 'px';
1459
+ this.contextMenuPosition.y = event.clientY + 'px';
1460
+ // как это (menuData) использовать в шаблоне не понятно, поэтому использую this.itemForMenu
1461
+ // https://www.concretepage.com/angular-material/passing-data-to-mat-menu-angular-material
1462
+ const contextMenu = this.contextMenu();
1463
+ if (contextMenu) {
1464
+ contextMenu.menuData = { itemForMenu };
1465
+ contextMenu.menu?.focusFirstItem('mouse');
1466
+ contextMenu.openMenu();
1467
+ }
1468
+ }
1469
+ getTotal(columnName) {
1470
+ const arr = this.dataSource.data
1471
+ .filter(t => typeof t[columnName] === 'number')
1472
+ .map(t => t[columnName]);
1473
+ if (arr.length === 0)
1474
+ return '';
1475
+ else
1476
+ return arr.reduce((acc, value) => acc + value, 0);
1477
+ }
1478
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1479
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TableComponent, isStandalone: true, selector: "ngx-uik-table", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, length: { classPropertyName: "length", publicName: "length", isSignal: true, isRequired: false, transformFunction: null }, columnOptions: { classPropertyName: "columnOptions", publicName: "columnOptions", isSignal: true, isRequired: false, transformFunction: null }, tableState: { classPropertyName: "tableState", publicName: "tableState", isSignal: true, isRequired: true, transformFunction: null }, allowMultiSelect: { classPropertyName: "allowMultiSelect", publicName: "allowMultiSelect", isSignal: true, isRequired: false, transformFunction: null }, opt: { classPropertyName: "opt", publicName: "opt", isSignal: true, isRequired: false, transformFunction: null }, rowDblClickedDisable: { classPropertyName: "rowDblClickedDisable", publicName: "rowDblClickedDisable", isSignal: true, isRequired: false, transformFunction: null }, footer: { classPropertyName: "footer", publicName: "footer", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { pageStateChange: "pageStateChange", sortStateChange: "sortStateChange", selectionChange: "selectionChange", rowDoubleClicked: "rowDoubleClicked" }, viewQueries: [{ propertyName: "sort", first: true, predicate: MatSort, descendants: true, isSignal: true }, { propertyName: "paginator", first: true, predicate: MatPaginator, descendants: true, isSignal: true }, { propertyName: "contextMenu", first: true, predicate: MatMenuTrigger, descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"component-container\">\r\n <div class=\"table-container\">\r\n <table mat-table [dataSource]=\"dataSource\"\r\n matSort\r\n [matSortActive]=\"sortState().sortActive || ''\"\r\n [matSortDirection]=\"sortState().sortDirection\"\r\n matSortDisableClear>\r\n\r\n <!-- \u0412\u044B\u0431\u043E\u0440 \u0441\u0442\u0440\u043E\u043A\u0438 Column -->\r\n <ng-container matColumnDef=\"select\">\r\n <th mat-header-cell *matHeaderCellDef>\r\n @if (allowMultiSelect()) {\r\n <mat-checkbox (change)=\"$event ? masterToggle() : null\" [checked]=\"selection.hasValue() && isAllSelected()\"\r\n [indeterminate]=\"selection.hasValue() && !isAllSelected()\">\r\n </mat-checkbox>\r\n }\r\n </th>\r\n <td mat-cell *matCellDef=\"let row\">\r\n <mat-checkbox (click)=\"$event.stopPropagation()\" (change)=\"$event ? selection.toggle(row) : null\"\r\n [checked]=\"selection.isSelected(row)\">\r\n </mat-checkbox>\r\n </td>\r\n @if (footer()) {\r\n <td mat-footer-cell *matFooterCellDef></td>\r\n }\r\n </ng-container>\r\n\r\n @for (item of columnOptions(); track item) {\r\n <ng-container matColumnDef={{item.name}}>\r\n <th mat-header-cell *matHeaderCellDef mat-sort-header [disabled]=\"item.titleSortDisable\">{{item.title}}</th>\r\n @if (!item.format) {\r\n <td mat-cell *matCellDef=\"let element\" (contextmenu)=\"onContextMenu($event, element)\" [matTooltip]=\"item.tooltip ?? ''\">\r\n {{element[item.name]}}\r\n </td>\r\n @if (footer()) {\r\n <td mat-footer-cell *matFooterCellDef>\r\n @if (item.footer) {\r\n <strong>{{ getTotal(item.name) }}</strong>\r\n }\r\n @if (item.footerTitle) {\r\n <strong>{{ item.footerTitle }}</strong>\r\n }\r\n </td>\r\n } \r\n }\r\n @if (item.format === 'pre-wrap') {\r\n <td mat-cell *matCellDef=\"let element\" (contextmenu)=\"onContextMenu($event, element)\" class=\"pre-wrap\" [matTooltip]=\"item.tooltip ?? ''\">\r\n {{element[item.name]}}\r\n </td>\r\n @if (footer()) {\r\n <td mat-footer-cell *matFooterCellDef>\r\n @if (item.footerTitle) {\r\n <strong>{{ item.footerTitle }}</strong>\r\n }\r\n </td>\r\n }\r\n }\r\n @if (item.format === 'link') {\r\n <td mat-cell *matCellDef=\"let element\" (contextmenu)=\"onContextMenu($event, element)\" [matTooltip]=\"item.tooltip ?? ''\">\r\n <a [href]=\"element[item.name]\" target=\"_blank\">{{element[item.name]}}</a>\r\n </td>\r\n @if (footer()) {\r\n <td mat-footer-cell *matFooterCellDef>\r\n @if (item.footerTitle) {\r\n <strong>{{ item.footerTitle }}</strong>\r\n }\r\n </td>\r\n }\r\n }\r\n @if (item.format === 'linkIcon') {\r\n <td mat-cell *matCellDef=\"let element\" (contextmenu)=\"onContextMenu($event, element)\" [matTooltip]=\"item.tooltip ?? ''\">\r\n @if (element[item.name]) {\r\n <a [href]=\"element[item.name]\" target=\"_blank\">\r\n @if (item.icon) {\r\n <mat-icon [class]=\"item.classList ? item.classList : ''\" >{{item.icon}}</mat-icon>\r\n } \r\n @if (item.symbol) {\r\n <span [class]=\"item.classList ? item.classList : ''\" >{{item.symbol}}</span>\r\n }\r\n </a>\r\n }\r\n </td>\r\n @if (footer()) {\r\n <td mat-footer-cell *matFooterCellDef>\r\n @if (item.footerTitle) {\r\n <strong>{{ item.footerTitle }}</strong>\r\n }\r\n </td>\r\n }\r\n }\r\n @if (item.format === 'routerLink') {\r\n <td mat-cell *matCellDef=\"let element\" (contextmenu)=\"onContextMenu($event, element)\" [matTooltip]=\"item.tooltip ?? ''\">\r\n <a [routerLink]=\"[element[item.name]]\">{{element[item.name]}}</a>\r\n </td>\r\n @if (footer()) {\r\n <td mat-footer-cell *matFooterCellDef>\r\n @if (item.footerTitle) {\r\n <strong>{{ item.footerTitle }}</strong>\r\n }\r\n </td>\r\n }\r\n }\r\n @if (item.format === 'routerLinkIcon') {\r\n <td mat-cell *matCellDef=\"let element\" (contextmenu)=\"onContextMenu($event, element)\" [matTooltip]=\"item.tooltip ?? ''\">\r\n @if (element[item.name]) {\r\n <a [routerLink]=\"[element[item.name]]\">\r\n @if (item.icon) {\r\n <mat-icon [class]=\"item.classList ? item.classList : ''\" >{{item.icon}}</mat-icon>\r\n } \r\n @if (item.symbol) {\r\n <span [class]=\"item.classList ? item.classList : ''\" >{{item.symbol}}</span>\r\n }\r\n </a>\r\n }\r\n </td>\r\n @if (footer()) {\r\n <td mat-footer-cell *matFooterCellDef>\r\n @if (item.footerTitle) {\r\n <strong>{{ item.footerTitle }}</strong>\r\n }\r\n </td>\r\n }\r\n }\r\n @if (item.format === 'checkbox') {\r\n <td mat-cell *matCellDef=\"let element\" (contextmenu)=\"onContextMenu($event, element)\" [matTooltip]=\"item.tooltip ?? ''\">\r\n <mat-checkbox [checked]=\"element[item.name] === 1\" [disabled]=\"true\"></mat-checkbox>\r\n </td>\r\n @if (footer()) {\r\n <td mat-footer-cell *matFooterCellDef>\r\n @if (item.footerTitle) {\r\n <strong>{{ item.footerTitle }}</strong>\r\n }\r\n </td>\r\n }\r\n }\r\n @if (item.format === 'icon') {\r\n <td mat-cell *matCellDef=\"let element\" (contextmenu)=\"onContextMenu($event, element)\" [matTooltip]=\"item.tooltip ?? ''\">\r\n @if (item.icon) {\r\n <mat-icon [class]=\"item.classList ? item.classList : ''\" >{{item.icon}}</mat-icon>\r\n } \r\n @if (item.symbol) {\r\n <span [class]=\"item.classList ? item.classList : ''\" >{{item.symbol}}</span>\r\n }\r\n </td>\r\n @if (footer()) {\r\n <td mat-footer-cell *matFooterCellDef>\r\n @if (item.footerTitle) {\r\n <strong>{{ item.footerTitle }}</strong>\r\n }\r\n </td>\r\n }\r\n }\r\n @if (item.format === 'icons') {\r\n <td mat-cell *matCellDef=\"let element\" (contextmenu)=\"onContextMenu($event, element)\">\r\n @if (item.icons) {\r\n <mat-icon [class]=\"item.classList ? item.classList[element[item.name]] : ''\" \r\n [matTooltip]=\"item.tooltips ? item.tooltips[element[item.name]] : ''\">{{item.icons[element[item.name]]}}</mat-icon>\r\n } \r\n @if (item.symbols) {\r\n <span [class]=\"item.classList ? item.classList[element[item.name]] : ''\" >{{item.symbols[element[item.name]]}}</span>\r\n }\r\n </td>\r\n @if (footer()) {\r\n <td mat-footer-cell *matFooterCellDef>\r\n @if (item.footerTitle) {\r\n <strong>{{ item.footerTitle }}</strong>\r\n }\r\n </td>\r\n }\r\n }\r\n @if (item.format === 'actions') {\r\n <td mat-cell *matCellDef=\"let element\" (contextmenu)=\"onContextMenu($event, element)\">\r\n @if (item.actions) {\r\n <div class=\"actions-container\">\r\n @for (action of item.actions; track action) {\r\n @if (!(action.hideFn ? action.hideFn(element) : action.hide)) {\r\n <button mat-icon-button\r\n (click)=\"action.onClickFn ? action.onClickFn(element) : ''\"\r\n (mousedown)=\"action.onClickMiddleFn ? action.onClickMiddleFn($event, element) : ''\"\r\n [disabled]=\"action.disabledFn ? action.disabledFn(element) : action.disabled\"\r\n [matTooltip]=\"action.tooltip ? action.tooltip : ''\" >\r\n @if (action.icon) {\r\n <mat-icon [class]=\"action.classList ? action.classList : ''\" >{{action.icon}}</mat-icon>\r\n }\r\n @if (action.symbol) {\r\n <span [class]=\"action.classList ? action.classList : ''\" >{{action.symbol}}</span>\r\n }\r\n {{ action.title }}\r\n </button>\r\n }\r\n }\r\n </div>\r\n } \r\n </td>\r\n @if (footer()) {\r\n <td mat-footer-cell *matFooterCellDef>\r\n @if (item.footerTitle) {\r\n <strong>{{ item.footerTitle }}</strong>\r\n }\r\n </td>\r\n }\r\n }\r\n @if (item.format === 'image') {\r\n <td mat-cell *matCellDef=\"let element\" (contextmenu)=\"onContextMenu($event, element)\" [matTooltip]=\"item.tooltip ?? ''\">\r\n @if (element[item.name]) {\r\n <img\r\n [src]=\"element[item.name]\"\r\n [alt]=\"item.imageAlt && element[item.imageAlt] ? element[item.imageAlt] : ''\"\r\n [class]=\"item.classList ? item.classList : ''\"\r\n />\r\n } \r\n </td>\r\n @if (footer()) {\r\n <td mat-footer-cell *matFooterCellDef>\r\n @if (item.footerTitle) {\r\n <strong>{{ item.footerTitle }}</strong>\r\n }\r\n </td>\r\n }\r\n }\r\n </ng-container>\r\n }\r\n\r\n <tr class=\"mat-row\" *matNoDataRow>\r\n <td class=\"mat-cell\" colspan=\"9999\">\r\n \u041D\u0435\u0442 \u0434\u0430\u043D\u043D\u044B\u0445 \u0434\u043B\u044F \u043E\u0442\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u044F\r\n </td>\r\n </tr>\r\n\r\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns; sticky: true\"></tr>\r\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\" \r\n (click)=\"onRowClicked(row)\" (dblclick)=\"onRowDblClicked(row)\" \r\n class=\"element-row\" [class.selected-row]=\"selection.isSelected(row)\">\r\n </tr>\r\n @if (footer()) {\r\n <tr mat-footer-row *matFooterRowDef=\"displayedColumns; sticky: true\"></tr>\r\n }\r\n </table>\r\n <div style=\"visibility: hidden; position: fixed\"\r\n [style.left]=\"contextMenuPosition.x\"\r\n [style.top]=\"contextMenuPosition.y\"\r\n [matMenuTriggerFor]=\"contextMenu\" #menuTrigger=\"matMenuTrigger\">\r\n </div>\r\n <mat-menu #contextMenu=\"matMenu\">\r\n <ng-template matMenuContent let-id=\"id\">\r\n @for (menuItem of opt(); track menuItem) {\r\n @if (menuItem.title === '-' && !(menuItem.hideFn ? menuItem.hideFn(itemForMenu) : menuItem.hide)) {\r\n <mat-divider></mat-divider>\r\n }\r\n @if (menuItem.title !== '-' && !(menuItem.hideFn ? menuItem.hideFn(itemForMenu) : menuItem.hide)) {\r\n <button mat-menu-item\r\n (click)=\"menuItem.onClickFn ? menuItem.onClickFn(itemForMenu) : ''\"\r\n (mousedown)=\"menuItem.onClickMiddleFn ? menuItem.onClickMiddleFn($event, itemForMenu, menuTrigger) : ''\"\r\n [disabled]=\"menuItem.disabledFn ? menuItem.disabledFn(itemForMenu) : menuItem.disabled\">\r\n @if (menuItem.icon) {\r\n <mat-icon [class]=\"menuItem.classList ? menuItem.classList : ''\">{{menuItem.icon}}</mat-icon>\r\n }\r\n @if (menuItem.symbol) {\r\n <span [class]=\"menuItem.classList ? menuItem.classList : ''\">{{menuItem.symbol}}</span>\r\n }\r\n {{ menuItem.title }}\r\n </button>\r\n }\r\n }\r\n </ng-template>\r\n </mat-menu>\r\n</div>\r\n\r\n\r\n<mat-paginator [length]=\"length()\"\r\n [pageIndex]=\"pageState().pageIndex || defaultPageIndex\"\r\n [pageSizeOptions]=\"[5, 10, 20, 50, 100]\"\r\n [pageSize]=\"pageState().pageSize || defaultPageSize\"\r\n showFirstLastButtons\r\n itemsPerPageLabel=\"\"\r\n></mat-paginator>\r\n</div>\r\n", styles: [".component-container{display:flex;flex-direction:column;height:100%}.table-container{display:flex;flex-direction:column;justify-content:space-between;flex:auto;margin:0 20px;overflow:auto;height:400px}.center{position:absolute;inset:0 0 56px;background:#00000026;z-index:1;display:flex;align-items:center;justify-content:center}.mat-column-select{overflow:initial}tr.mat-footer-row{font-weight:700;height:56px}.mat-table{overflow-x:scroll}.mat-cell,.mat-header-cell{word-wrap:initial;display:table-cell;padding:0 10px;line-break:unset;white-space:nowrap;overflow:hidden;vertical-align:middle}.mat-row,.mat-header-row{display:table-row}tr.element-row:not(.selected-row):hover{background:#f5f5f5}tr.element-row:not(.selected-row):active{background:#efefef}.selected-row{background-color:#eee}.fact-done-row{background-color:#eefdec}a,a:visited,a:hover,a:active{color:inherit}.pre-wrap{white-space:pre-wrap}.actions-container{display:flex;column-gap:5px}\n"], dependencies: [{ kind: "component", type: MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: MatSort, selector: "[matSort]", inputs: ["matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear", "matSortDisabled"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "directive", type: MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "component", type: MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "directive", type: MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: MatSortHeader, selector: "[mat-sort-header]", inputs: ["mat-sort-header", "arrowPosition", "start", "disabled", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: MatNoDataRow, selector: "ng-template[matNoDataRow]" }, { kind: "directive", type: MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "component", type: MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "directive", type: MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "component", type: MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "directive", type: MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "component", type: MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "directive", type: MatMenuContent, selector: "ng-template[matMenuContent]" }, { kind: "component", type: MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "component", type: MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "component", type: MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "directive", type: MatFooterRowDef, selector: "[matFooterRowDef]", inputs: ["matFooterRowDef", "matFooterRowDefSticky"] }, { kind: "component", type: MatFooterRow, selector: "mat-footer-row, tr[mat-footer-row]", exportAs: ["matFooterRow"] }, { kind: "directive", type: MatFooterCellDef, selector: "[matFooterCellDef]" }, { kind: "directive", type: MatFooterCell, selector: "mat-footer-cell, td[mat-footer-cell]" }, { kind: "ngmodule", type: MatTableModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i1$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }] });
1480
+ }
1481
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TableComponent, decorators: [{
1482
+ type: Component,
1483
+ args: [{ selector: 'ngx-uik-table', imports: [MatTable, MatSort, MatColumnDef, MatHeaderCellDef, MatHeaderCell, MatCheckbox, MatCellDef, MatCell,
1484
+ MatSortHeader, MatIcon, RouterLink, MatNoDataRow, MatHeaderRowDef, MatHeaderRow, MatRowDef, MatRow,
1485
+ MatMenuTrigger, MatMenu, MatMenuContent, MatDivider, MatMenuItem, MatPaginator, MatFooterRowDef, MatFooterRow,
1486
+ MatFooterCellDef, MatFooterCell, MatTableModule, MatTooltipModule, MatIconButton], template: "<div class=\"component-container\">\r\n <div class=\"table-container\">\r\n <table mat-table [dataSource]=\"dataSource\"\r\n matSort\r\n [matSortActive]=\"sortState().sortActive || ''\"\r\n [matSortDirection]=\"sortState().sortDirection\"\r\n matSortDisableClear>\r\n\r\n <!-- \u0412\u044B\u0431\u043E\u0440 \u0441\u0442\u0440\u043E\u043A\u0438 Column -->\r\n <ng-container matColumnDef=\"select\">\r\n <th mat-header-cell *matHeaderCellDef>\r\n @if (allowMultiSelect()) {\r\n <mat-checkbox (change)=\"$event ? masterToggle() : null\" [checked]=\"selection.hasValue() && isAllSelected()\"\r\n [indeterminate]=\"selection.hasValue() && !isAllSelected()\">\r\n </mat-checkbox>\r\n }\r\n </th>\r\n <td mat-cell *matCellDef=\"let row\">\r\n <mat-checkbox (click)=\"$event.stopPropagation()\" (change)=\"$event ? selection.toggle(row) : null\"\r\n [checked]=\"selection.isSelected(row)\">\r\n </mat-checkbox>\r\n </td>\r\n @if (footer()) {\r\n <td mat-footer-cell *matFooterCellDef></td>\r\n }\r\n </ng-container>\r\n\r\n @for (item of columnOptions(); track item) {\r\n <ng-container matColumnDef={{item.name}}>\r\n <th mat-header-cell *matHeaderCellDef mat-sort-header [disabled]=\"item.titleSortDisable\">{{item.title}}</th>\r\n @if (!item.format) {\r\n <td mat-cell *matCellDef=\"let element\" (contextmenu)=\"onContextMenu($event, element)\" [matTooltip]=\"item.tooltip ?? ''\">\r\n {{element[item.name]}}\r\n </td>\r\n @if (footer()) {\r\n <td mat-footer-cell *matFooterCellDef>\r\n @if (item.footer) {\r\n <strong>{{ getTotal(item.name) }}</strong>\r\n }\r\n @if (item.footerTitle) {\r\n <strong>{{ item.footerTitle }}</strong>\r\n }\r\n </td>\r\n } \r\n }\r\n @if (item.format === 'pre-wrap') {\r\n <td mat-cell *matCellDef=\"let element\" (contextmenu)=\"onContextMenu($event, element)\" class=\"pre-wrap\" [matTooltip]=\"item.tooltip ?? ''\">\r\n {{element[item.name]}}\r\n </td>\r\n @if (footer()) {\r\n <td mat-footer-cell *matFooterCellDef>\r\n @if (item.footerTitle) {\r\n <strong>{{ item.footerTitle }}</strong>\r\n }\r\n </td>\r\n }\r\n }\r\n @if (item.format === 'link') {\r\n <td mat-cell *matCellDef=\"let element\" (contextmenu)=\"onContextMenu($event, element)\" [matTooltip]=\"item.tooltip ?? ''\">\r\n <a [href]=\"element[item.name]\" target=\"_blank\">{{element[item.name]}}</a>\r\n </td>\r\n @if (footer()) {\r\n <td mat-footer-cell *matFooterCellDef>\r\n @if (item.footerTitle) {\r\n <strong>{{ item.footerTitle }}</strong>\r\n }\r\n </td>\r\n }\r\n }\r\n @if (item.format === 'linkIcon') {\r\n <td mat-cell *matCellDef=\"let element\" (contextmenu)=\"onContextMenu($event, element)\" [matTooltip]=\"item.tooltip ?? ''\">\r\n @if (element[item.name]) {\r\n <a [href]=\"element[item.name]\" target=\"_blank\">\r\n @if (item.icon) {\r\n <mat-icon [class]=\"item.classList ? item.classList : ''\" >{{item.icon}}</mat-icon>\r\n } \r\n @if (item.symbol) {\r\n <span [class]=\"item.classList ? item.classList : ''\" >{{item.symbol}}</span>\r\n }\r\n </a>\r\n }\r\n </td>\r\n @if (footer()) {\r\n <td mat-footer-cell *matFooterCellDef>\r\n @if (item.footerTitle) {\r\n <strong>{{ item.footerTitle }}</strong>\r\n }\r\n </td>\r\n }\r\n }\r\n @if (item.format === 'routerLink') {\r\n <td mat-cell *matCellDef=\"let element\" (contextmenu)=\"onContextMenu($event, element)\" [matTooltip]=\"item.tooltip ?? ''\">\r\n <a [routerLink]=\"[element[item.name]]\">{{element[item.name]}}</a>\r\n </td>\r\n @if (footer()) {\r\n <td mat-footer-cell *matFooterCellDef>\r\n @if (item.footerTitle) {\r\n <strong>{{ item.footerTitle }}</strong>\r\n }\r\n </td>\r\n }\r\n }\r\n @if (item.format === 'routerLinkIcon') {\r\n <td mat-cell *matCellDef=\"let element\" (contextmenu)=\"onContextMenu($event, element)\" [matTooltip]=\"item.tooltip ?? ''\">\r\n @if (element[item.name]) {\r\n <a [routerLink]=\"[element[item.name]]\">\r\n @if (item.icon) {\r\n <mat-icon [class]=\"item.classList ? item.classList : ''\" >{{item.icon}}</mat-icon>\r\n } \r\n @if (item.symbol) {\r\n <span [class]=\"item.classList ? item.classList : ''\" >{{item.symbol}}</span>\r\n }\r\n </a>\r\n }\r\n </td>\r\n @if (footer()) {\r\n <td mat-footer-cell *matFooterCellDef>\r\n @if (item.footerTitle) {\r\n <strong>{{ item.footerTitle }}</strong>\r\n }\r\n </td>\r\n }\r\n }\r\n @if (item.format === 'checkbox') {\r\n <td mat-cell *matCellDef=\"let element\" (contextmenu)=\"onContextMenu($event, element)\" [matTooltip]=\"item.tooltip ?? ''\">\r\n <mat-checkbox [checked]=\"element[item.name] === 1\" [disabled]=\"true\"></mat-checkbox>\r\n </td>\r\n @if (footer()) {\r\n <td mat-footer-cell *matFooterCellDef>\r\n @if (item.footerTitle) {\r\n <strong>{{ item.footerTitle }}</strong>\r\n }\r\n </td>\r\n }\r\n }\r\n @if (item.format === 'icon') {\r\n <td mat-cell *matCellDef=\"let element\" (contextmenu)=\"onContextMenu($event, element)\" [matTooltip]=\"item.tooltip ?? ''\">\r\n @if (item.icon) {\r\n <mat-icon [class]=\"item.classList ? item.classList : ''\" >{{item.icon}}</mat-icon>\r\n } \r\n @if (item.symbol) {\r\n <span [class]=\"item.classList ? item.classList : ''\" >{{item.symbol}}</span>\r\n }\r\n </td>\r\n @if (footer()) {\r\n <td mat-footer-cell *matFooterCellDef>\r\n @if (item.footerTitle) {\r\n <strong>{{ item.footerTitle }}</strong>\r\n }\r\n </td>\r\n }\r\n }\r\n @if (item.format === 'icons') {\r\n <td mat-cell *matCellDef=\"let element\" (contextmenu)=\"onContextMenu($event, element)\">\r\n @if (item.icons) {\r\n <mat-icon [class]=\"item.classList ? item.classList[element[item.name]] : ''\" \r\n [matTooltip]=\"item.tooltips ? item.tooltips[element[item.name]] : ''\">{{item.icons[element[item.name]]}}</mat-icon>\r\n } \r\n @if (item.symbols) {\r\n <span [class]=\"item.classList ? item.classList[element[item.name]] : ''\" >{{item.symbols[element[item.name]]}}</span>\r\n }\r\n </td>\r\n @if (footer()) {\r\n <td mat-footer-cell *matFooterCellDef>\r\n @if (item.footerTitle) {\r\n <strong>{{ item.footerTitle }}</strong>\r\n }\r\n </td>\r\n }\r\n }\r\n @if (item.format === 'actions') {\r\n <td mat-cell *matCellDef=\"let element\" (contextmenu)=\"onContextMenu($event, element)\">\r\n @if (item.actions) {\r\n <div class=\"actions-container\">\r\n @for (action of item.actions; track action) {\r\n @if (!(action.hideFn ? action.hideFn(element) : action.hide)) {\r\n <button mat-icon-button\r\n (click)=\"action.onClickFn ? action.onClickFn(element) : ''\"\r\n (mousedown)=\"action.onClickMiddleFn ? action.onClickMiddleFn($event, element) : ''\"\r\n [disabled]=\"action.disabledFn ? action.disabledFn(element) : action.disabled\"\r\n [matTooltip]=\"action.tooltip ? action.tooltip : ''\" >\r\n @if (action.icon) {\r\n <mat-icon [class]=\"action.classList ? action.classList : ''\" >{{action.icon}}</mat-icon>\r\n }\r\n @if (action.symbol) {\r\n <span [class]=\"action.classList ? action.classList : ''\" >{{action.symbol}}</span>\r\n }\r\n {{ action.title }}\r\n </button>\r\n }\r\n }\r\n </div>\r\n } \r\n </td>\r\n @if (footer()) {\r\n <td mat-footer-cell *matFooterCellDef>\r\n @if (item.footerTitle) {\r\n <strong>{{ item.footerTitle }}</strong>\r\n }\r\n </td>\r\n }\r\n }\r\n @if (item.format === 'image') {\r\n <td mat-cell *matCellDef=\"let element\" (contextmenu)=\"onContextMenu($event, element)\" [matTooltip]=\"item.tooltip ?? ''\">\r\n @if (element[item.name]) {\r\n <img\r\n [src]=\"element[item.name]\"\r\n [alt]=\"item.imageAlt && element[item.imageAlt] ? element[item.imageAlt] : ''\"\r\n [class]=\"item.classList ? item.classList : ''\"\r\n />\r\n } \r\n </td>\r\n @if (footer()) {\r\n <td mat-footer-cell *matFooterCellDef>\r\n @if (item.footerTitle) {\r\n <strong>{{ item.footerTitle }}</strong>\r\n }\r\n </td>\r\n }\r\n }\r\n </ng-container>\r\n }\r\n\r\n <tr class=\"mat-row\" *matNoDataRow>\r\n <td class=\"mat-cell\" colspan=\"9999\">\r\n \u041D\u0435\u0442 \u0434\u0430\u043D\u043D\u044B\u0445 \u0434\u043B\u044F \u043E\u0442\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u044F\r\n </td>\r\n </tr>\r\n\r\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns; sticky: true\"></tr>\r\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\" \r\n (click)=\"onRowClicked(row)\" (dblclick)=\"onRowDblClicked(row)\" \r\n class=\"element-row\" [class.selected-row]=\"selection.isSelected(row)\">\r\n </tr>\r\n @if (footer()) {\r\n <tr mat-footer-row *matFooterRowDef=\"displayedColumns; sticky: true\"></tr>\r\n }\r\n </table>\r\n <div style=\"visibility: hidden; position: fixed\"\r\n [style.left]=\"contextMenuPosition.x\"\r\n [style.top]=\"contextMenuPosition.y\"\r\n [matMenuTriggerFor]=\"contextMenu\" #menuTrigger=\"matMenuTrigger\">\r\n </div>\r\n <mat-menu #contextMenu=\"matMenu\">\r\n <ng-template matMenuContent let-id=\"id\">\r\n @for (menuItem of opt(); track menuItem) {\r\n @if (menuItem.title === '-' && !(menuItem.hideFn ? menuItem.hideFn(itemForMenu) : menuItem.hide)) {\r\n <mat-divider></mat-divider>\r\n }\r\n @if (menuItem.title !== '-' && !(menuItem.hideFn ? menuItem.hideFn(itemForMenu) : menuItem.hide)) {\r\n <button mat-menu-item\r\n (click)=\"menuItem.onClickFn ? menuItem.onClickFn(itemForMenu) : ''\"\r\n (mousedown)=\"menuItem.onClickMiddleFn ? menuItem.onClickMiddleFn($event, itemForMenu, menuTrigger) : ''\"\r\n [disabled]=\"menuItem.disabledFn ? menuItem.disabledFn(itemForMenu) : menuItem.disabled\">\r\n @if (menuItem.icon) {\r\n <mat-icon [class]=\"menuItem.classList ? menuItem.classList : ''\">{{menuItem.icon}}</mat-icon>\r\n }\r\n @if (menuItem.symbol) {\r\n <span [class]=\"menuItem.classList ? menuItem.classList : ''\">{{menuItem.symbol}}</span>\r\n }\r\n {{ menuItem.title }}\r\n </button>\r\n }\r\n }\r\n </ng-template>\r\n </mat-menu>\r\n</div>\r\n\r\n\r\n<mat-paginator [length]=\"length()\"\r\n [pageIndex]=\"pageState().pageIndex || defaultPageIndex\"\r\n [pageSizeOptions]=\"[5, 10, 20, 50, 100]\"\r\n [pageSize]=\"pageState().pageSize || defaultPageSize\"\r\n showFirstLastButtons\r\n itemsPerPageLabel=\"\"\r\n></mat-paginator>\r\n</div>\r\n", styles: [".component-container{display:flex;flex-direction:column;height:100%}.table-container{display:flex;flex-direction:column;justify-content:space-between;flex:auto;margin:0 20px;overflow:auto;height:400px}.center{position:absolute;inset:0 0 56px;background:#00000026;z-index:1;display:flex;align-items:center;justify-content:center}.mat-column-select{overflow:initial}tr.mat-footer-row{font-weight:700;height:56px}.mat-table{overflow-x:scroll}.mat-cell,.mat-header-cell{word-wrap:initial;display:table-cell;padding:0 10px;line-break:unset;white-space:nowrap;overflow:hidden;vertical-align:middle}.mat-row,.mat-header-row{display:table-row}tr.element-row:not(.selected-row):hover{background:#f5f5f5}tr.element-row:not(.selected-row):active{background:#efefef}.selected-row{background-color:#eee}.fact-done-row{background-color:#eefdec}a,a:visited,a:hover,a:active{color:inherit}.pre-wrap{white-space:pre-wrap}.actions-container{display:flex;column-gap:5px}\n"] }]
1487
+ }], ctorParameters: () => [], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], length: [{ type: i0.Input, args: [{ isSignal: true, alias: "length", required: false }] }], columnOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnOptions", required: false }] }], tableState: [{ type: i0.Input, args: [{ isSignal: true, alias: "tableState", required: true }] }], allowMultiSelect: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowMultiSelect", required: false }] }], opt: [{ type: i0.Input, args: [{ isSignal: true, alias: "opt", required: false }] }], rowDblClickedDisable: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowDblClickedDisable", required: false }] }], footer: [{ type: i0.Input, args: [{ isSignal: true, alias: "footer", required: false }] }], pageStateChange: [{ type: i0.Output, args: ["pageStateChange"] }], sortStateChange: [{ type: i0.Output, args: ["sortStateChange"] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], rowDoubleClicked: [{ type: i0.Output, args: ["rowDoubleClicked"] }], sort: [{ type: i0.ViewChild, args: [i0.forwardRef(() => MatSort), { isSignal: true }] }], paginator: [{ type: i0.ViewChild, args: [i0.forwardRef(() => MatPaginator), { isSignal: true }] }], contextMenu: [{ type: i0.ViewChild, args: [i0.forwardRef(() => MatMenuTrigger), { isSignal: true }] }] } });
1488
+
1489
+ class LoaderService {
1490
+ overlayRef = null;
1491
+ overlay = inject(Overlay);
1492
+ show() {
1493
+ if (!this.overlayRef) {
1494
+ this.overlayRef = this.overlay.create();
1495
+ }
1496
+ const spinnerOverlayPortal = new ComponentPortal(ProgressSpinnerComponent);
1497
+ // Исправление ошибки Expression has changed after it was checked
1498
+ setTimeout(() => {
1499
+ if (!this.overlayRef?.hasAttached()) {
1500
+ this.overlayRef?.attach(spinnerOverlayPortal);
1501
+ }
1502
+ });
1503
+ }
1504
+ hide() {
1505
+ if (this.overlayRef) {
1506
+ this.overlayRef.detach();
1507
+ }
1508
+ }
1509
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: LoaderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1510
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: LoaderService, providedIn: 'root' });
1511
+ }
1512
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: LoaderService, decorators: [{
1513
+ type: Injectable,
1514
+ args: [{
1515
+ providedIn: 'root'
1516
+ }]
1517
+ }] });
1518
+
1519
+ class ExportService {
1520
+ // Экспорт в CSV
1521
+ exportCSV(data, filename = 'data', arrHeader, newHeaders) {
1522
+ const csvData = this.convertToCSV(data, arrHeader, newHeaders);
1523
+ console.log(csvData);
1524
+ const blob = new Blob(['\ufeff' + csvData], { type: 'text/csv;charset=utf-8;' });
1525
+ const dwldLink = document.createElement('a');
1526
+ const url = URL.createObjectURL(blob);
1527
+ const isSafariBrowser = navigator.userAgent.indexOf('Safari') !== -1 && navigator.userAgent.indexOf('Chrome') === -1;
1528
+ if (isSafariBrowser) { //if Safari open in new window to save file with random filename.
1529
+ dwldLink.setAttribute('target', '_blank');
1530
+ }
1531
+ dwldLink.setAttribute('href', url);
1532
+ dwldLink.setAttribute('download', filename + '.csv');
1533
+ dwldLink.style.visibility = 'hidden';
1534
+ document.body.appendChild(dwldLink);
1535
+ dwldLink.click();
1536
+ document.body.removeChild(dwldLink);
1537
+ }
1538
+ convertToCSV(objArray, headerList, newHeaders) {
1539
+ const array = typeof objArray != 'object' ? JSON.parse(objArray) : objArray;
1540
+ let str = '';
1541
+ let row = 'S.No,';
1542
+ for (const index in newHeaders) {
1543
+ if (Object.prototype.hasOwnProperty.call(newHeaders, index)) {
1544
+ row += newHeaders[index] + ',';
1545
+ }
1546
+ }
1547
+ row = row.slice(0, -1);
1548
+ str += row + '\r\n';
1549
+ for (let i = 0; i < array.length; i++) {
1550
+ let line = (i + 1) + '';
1551
+ for (const index in headerList) {
1552
+ if (Object.prototype.hasOwnProperty.call(newHeaders, index)) {
1553
+ const head = headerList[index];
1554
+ line += ',' + array[i][head];
1555
+ }
1556
+ }
1557
+ str += line + '\r\n';
1558
+ }
1559
+ return str;
1560
+ }
1561
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: ExportService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1562
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: ExportService, providedIn: 'root' });
1563
+ }
1564
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: ExportService, decorators: [{
1565
+ type: Injectable,
1566
+ args: [{
1567
+ providedIn: 'root'
1568
+ }]
1569
+ }] });
1570
+
1571
+ class SseService {
1572
+ zone = inject(NgZone);
1573
+ eventSource = null;
1574
+ isConnected = false;
1575
+ constructor() { }
1576
+ createSseEventSource(baseUrl, user, topic) {
1577
+ const subject = new ReplaySubject(1);
1578
+ // Close any existing connection
1579
+ this.closeSseEventSource();
1580
+ const topicUri = topic.getTopic(baseUrl, user);
1581
+ // environment.sse_url
1582
+ this.eventSource = new EventSource(topicUri
1583
+ //, {withCredentials: true}
1584
+ );
1585
+ if (this.eventSource) {
1586
+ this.isConnected = true;
1587
+ // Listen for messages
1588
+ this.eventSource.onmessage = (event) => {
1589
+ console.log(event);
1590
+ const messageData = JSON.parse(event.data);
1591
+ this.zone.run(() => {
1592
+ subject.next(messageData);
1593
+ });
1594
+ };
1595
+ this.eventSource.onopen = () => {
1596
+ console.log('SSE connection opened.');
1597
+ };
1598
+ // Process error
1599
+ this.eventSource.onerror = (error) => {
1600
+ console.error('SSE error:', error);
1601
+ this.reconnectOnError(baseUrl, user, topic, subject);
1602
+ };
1603
+ }
1604
+ return subject.asObservable();
1605
+ }
1606
+ reconnectOnError(baseUrl, user, topic, subject) {
1607
+ this.closeSseEventSource();
1608
+ if (this.isConnected)
1609
+ return; // Prevent duplicate connections
1610
+ console.log('Reconnecting to SSE in 1 second...');
1611
+ setTimeout(() => {
1612
+ this.zone.run(() => {
1613
+ this.createSseEventSource(baseUrl, user, topic).subscribe(subject);
1614
+ });
1615
+ }, 1000);
1616
+ }
1617
+ closeSseEventSource() {
1618
+ if (this.eventSource) {
1619
+ this.eventSource.close();
1620
+ this.eventSource = null;
1621
+ this.isConnected = false;
1622
+ console.log('SSE Connection closed');
1623
+ }
1624
+ }
1625
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: SseService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1626
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: SseService, providedIn: 'root' });
1627
+ }
1628
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: SseService, decorators: [{
1629
+ type: Injectable,
1630
+ args: [{
1631
+ providedIn: 'root'
1632
+ }]
1633
+ }], ctorParameters: () => [] });
1634
+
1635
+ class LoginPageComponent {
1636
+ pending = false;
1637
+ error = '';
1638
+ isKiosk = false;
1639
+ /** Идентификатор АС */
1640
+ idCas = 0;
1641
+ /** Подписка на Идентификатор АС */
1642
+ sub;
1643
+ authService = inject(AuthService);
1644
+ route = inject(ActivatedRoute);
1645
+ loaderService = inject(LoaderService);
1646
+ constructor() {
1647
+ this.sub = this.route.data.subscribe(data => {
1648
+ this.idCas = data['idCas'];
1649
+ });
1650
+ }
1651
+ ngOnInit() {
1652
+ if (localStorage.getItem('id_human') || localStorage.getItem('kiosk-keyboard-layout')) {
1653
+ // this.isKiosk = true;
1654
+ }
1655
+ }
1656
+ ngOnDestroy() {
1657
+ this.sub.unsubscribe();
1658
+ }
1659
+ onSubmitError() {
1660
+ return () => {
1661
+ this.pending = false;
1662
+ this.loaderService.hide();
1663
+ };
1664
+ }
1665
+ onSubmit($event) {
1666
+ this.loaderService.show();
1667
+ this.pending = true;
1668
+ this.authService.login($event.username, $event.password, this.idCas, this.onSubmitError());
1669
+ }
1670
+ onSubmitPermit($event) {
1671
+ const permit = $event;
1672
+ this.authService.loginByPermit(permit, this.idCas);
1673
+ }
1674
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: LoginPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1675
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: LoginPageComponent, isStandalone: true, selector: "ngx-uik-login-page", ngImport: i0, template: "@if (!isKiosk) {\r\n <ngx-uik-login-form\r\n (submitted)=\"onSubmit($event)\"\r\n [pending]=\"pending\"\r\n [errorMessage]=\"error\">\r\n </ngx-uik-login-form>\r\n }\r\n @if (isKiosk) {\r\n <ngx-uik-permit-form\r\n (submitted)=\"onSubmitPermit($event)\"\r\n >\r\n </ngx-uik-permit-form>\r\n }", styles: [""], dependencies: [{ kind: "component", type: LoginFormComponent, selector: "ngx-uik-login-form", inputs: ["pending", "errorMessage"], outputs: ["submitted"] }, { kind: "component", type: PermitFormComponent, selector: "ngx-uik-permit-form", outputs: ["submitted"] }] });
1676
+ }
1677
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: LoginPageComponent, decorators: [{
1678
+ type: Component,
1679
+ args: [{ selector: 'ngx-uik-login-page', imports: [LoginFormComponent, PermitFormComponent], template: "@if (!isKiosk) {\r\n <ngx-uik-login-form\r\n (submitted)=\"onSubmit($event)\"\r\n [pending]=\"pending\"\r\n [errorMessage]=\"error\">\r\n </ngx-uik-login-form>\r\n }\r\n @if (isKiosk) {\r\n <ngx-uik-permit-form\r\n (submitted)=\"onSubmitPermit($event)\"\r\n >\r\n </ngx-uik-permit-form>\r\n }" }]
1680
+ }], ctorParameters: () => [] });
1681
+
1682
+ class DisableIfRoleDirective {
1683
+ roles = input([], { ...(ngDevMode ? { debugName: "roles" } : {}), alias: 'ngxUikDisableIfRole' });
1684
+ el = inject(ElementRef);
1685
+ authService = inject(AuthService);
1686
+ roleService = inject(RoleService);
1687
+ constructor() {
1688
+ effect(() => {
1689
+ const hasRequiredRole = this.roleService.hasRoles(this.authService.roles(), this.roles());
1690
+ // Блокируем, если ролей НЕТ
1691
+ const shouldDisable = !hasRequiredRole;
1692
+ // 2. Безопасное управление атрибутом для любых элементов
1693
+ const nativeEl = this.el.nativeElement;
1694
+ if ('disabled' in nativeEl) {
1695
+ nativeEl.disabled = shouldDisable;
1696
+ }
1697
+ else {
1698
+ // Для элементов вроде <a>, у которых нет свойства disabled в DOM API
1699
+ if (shouldDisable) {
1700
+ nativeEl.setAttribute('disabled', 'true');
1701
+ }
1702
+ else {
1703
+ nativeEl.removeAttribute('disabled');
1704
+ }
1705
+ }
1706
+ });
1707
+ }
1708
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DisableIfRoleDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1709
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.0", type: DisableIfRoleDirective, isStandalone: true, selector: "[ngxUikDisableIfRole]", inputs: { roles: { classPropertyName: "roles", publicName: "ngxUikDisableIfRole", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
1710
+ }
1711
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DisableIfRoleDirective, decorators: [{
1712
+ type: Directive,
1713
+ args: [{
1714
+ selector: '[ngxUikDisableIfRole]',
1715
+ standalone: true
1716
+ }]
1717
+ }], ctorParameters: () => [], propDecorators: { roles: [{ type: i0.Input, args: [{ isSignal: true, alias: "ngxUikDisableIfRole", required: false }] }] } });
1718
+
1719
+ class HideIfRoleNotDirective {
1720
+ roles = input([], { ...(ngDevMode ? { debugName: "roles" } : {}), alias: 'ngxUikHideIfRoleNot' });
1721
+ el = inject(ElementRef);
1722
+ authService = inject(AuthService);
1723
+ roleService = inject(RoleService);
1724
+ constructor() {
1725
+ effect(() => {
1726
+ // Элемент скрывается, если у пользователя нет ни одной роли из перереданных в "roles"
1727
+ // или в списке "roles" есть роль "hideRole".
1728
+ const isHide = this.roleService.isHideElement(this.roles(), this.authService.roles());
1729
+ // Управляем отображением. Пустая строка возвращает дефолтный CSS-стиль элемента.
1730
+ this.el.nativeElement.style.display = isHide ? 'none' : '';
1731
+ });
1732
+ }
1733
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: HideIfRoleNotDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1734
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.0", type: HideIfRoleNotDirective, isStandalone: true, selector: "[ngxUikHideIfRoleNot]", inputs: { roles: { classPropertyName: "roles", publicName: "ngxUikHideIfRoleNot", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
1735
+ }
1736
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: HideIfRoleNotDirective, decorators: [{
1737
+ type: Directive,
1738
+ args: [{
1739
+ selector: '[ngxUikHideIfRoleNot]',
1740
+ standalone: true
1741
+ }]
1742
+ }], ctorParameters: () => [], propDecorators: { roles: [{ type: i0.Input, args: [{ isSignal: true, alias: "ngxUikHideIfRoleNot", required: false }] }] } });
1743
+
1744
+ class SetValueDirective {
1745
+ value = input(undefined, { ...(ngDevMode ? { debugName: "value" } : {}), alias: 'setValue' });
1746
+ // 3. Используем опциональный inject, чтобы директива не падала, если формы нет
1747
+ ngControl = inject(NgControl, { optional: true });
1748
+ constructor() {
1749
+ effect(() => {
1750
+ // Эффект автоматически отслеживает изменение входного значения
1751
+ const val = this.value();
1752
+ if (this.ngControl?.control) {
1753
+ this.ngControl.control.setValue(val, { emitEvent: false });
1754
+ }
1755
+ });
1756
+ }
1757
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: SetValueDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1758
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.0", type: SetValueDirective, isStandalone: true, selector: "[setValue]", inputs: { value: { classPropertyName: "value", publicName: "setValue", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
1759
+ }
1760
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: SetValueDirective, decorators: [{
1761
+ type: Directive,
1762
+ args: [{
1763
+ selector: '[setValue]',
1764
+ standalone: true,
1765
+ }]
1766
+ }], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "setValue", required: false }] }] } });
1767
+
1768
+ const authGuard = (allowedRoles) => {
1769
+ return (route, state) => {
1770
+ const authService = inject(AuthService);
1771
+ const router = inject(Router);
1772
+ const isLogin = authService.loggedIn();
1773
+ if (!isLogin) {
1774
+ console.log('state.url =', state.url);
1775
+ // Если не зарегистрирован вернуть в форму авторизации
1776
+ return router.createUrlTree(['/login'], { queryParams: { returnUrl: state.url } });
1777
+ }
1778
+ return isLogin;
1779
+ };
1780
+ };
1781
+
1782
+ const redirectGuard = (route) => {
1783
+ const externalUrl = route.data?.['externalUrl'];
1784
+ if (externalUrl) {
1785
+ window.location.href = externalUrl;
1786
+ }
1787
+ return true;
1788
+ };
1789
+
1790
+ const roleGuard = (allowedRoles) => {
1791
+ return (route, state) => {
1792
+ const authService = inject(AuthService);
1793
+ const roleService = inject(RoleService);
1794
+ // Читаем роли из Сигнала
1795
+ const userRoles = authService.roles();
1796
+ // Проверяем доступ на основе аргумента allowedRoles
1797
+ return roleService.hasRoles(userRoles, allowedRoles);
1798
+ };
1799
+ };
1800
+
1801
+ /*
1802
+ * Public API Surface of uikit
1803
+ */
1804
+
1805
+ /**
1806
+ * Generated bundle index. Do not edit.
1807
+ */
1808
+
1809
+ export { Action, AvatarService, BaseEditClass, BaseFilterClass, BaseMatChipComponent, BaseNavBarMenuClass, BasePageClass, BaseSelectAutocompleteWithVsComponent, BaseSelectWithGroupComponent, BaseServiceClass, BaseToolbarComponent, DateRangeInputComponent, DialogAction, DialogComponent, DisableIfRoleDirective, EmptyComponent, EntityAction, ExportService, HideIfRoleNotDirective, LoaderService, LocalStorageService, LoginPageComponent, MY_FORMATS, NavBarComponent, NotFoundComponent, ProgressSpinnerComponent, SafePipe, SetValueDirective, SseService, TableComponent, TimePipe, TruncatePipe, authGuard, dateFormat, redirectGuard, roleGuard };
1810
+ //# sourceMappingURL=kuzntsv-uikit-ui.mjs.map