@webilix/ngx-table-m3 0.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.
Files changed (45) hide show
  1. package/README.md +6 -0
  2. package/fesm2022/webilix-ngx-table-m3.mjs +1258 -0
  3. package/fesm2022/webilix-ngx-table-m3.mjs.map +1 -0
  4. package/index.d.ts +5 -0
  5. package/lib/columns/column.action.d.ts +24 -0
  6. package/lib/columns/column.info.d.ts +9 -0
  7. package/lib/columns/column.interface.d.ts +46 -0
  8. package/lib/columns/date/column-date.component.d.ts +10 -0
  9. package/lib/columns/date/column-date.interface.d.ts +10 -0
  10. package/lib/columns/duration/column-duration.component.d.ts +10 -0
  11. package/lib/columns/duration/column-duration.interface.d.ts +9 -0
  12. package/lib/columns/index.d.ts +13 -0
  13. package/lib/columns/mobile/column-mobile.component.d.ts +10 -0
  14. package/lib/columns/mobile/column-mobile.interface.d.ts +9 -0
  15. package/lib/columns/number/column-number.component.d.ts +10 -0
  16. package/lib/columns/number/column-number.interface.d.ts +9 -0
  17. package/lib/columns/text/column-text.component.d.ts +10 -0
  18. package/lib/columns/text/column-text.interface.d.ts +8 -0
  19. package/lib/filters/date/filter-date.component.d.ts +13 -0
  20. package/lib/filters/date/filter-date.interface.d.ts +16 -0
  21. package/lib/filters/filter.component.d.ts +35 -0
  22. package/lib/filters/filter.info.d.ts +8 -0
  23. package/lib/filters/filter.interface.d.ts +24 -0
  24. package/lib/filters/filter.service.d.ts +18 -0
  25. package/lib/filters/index.d.ts +10 -0
  26. package/lib/filters/multi-select/filter-multi-select.component.d.ts +14 -0
  27. package/lib/filters/multi-select/filter-multi-select.interface.d.ts +19 -0
  28. package/lib/filters/search/filter-search.component.d.ts +20 -0
  29. package/lib/filters/search/filter-search.interface.d.ts +20 -0
  30. package/lib/filters/select/filter-select.component.d.ts +13 -0
  31. package/lib/filters/select/filter-select.interface.d.ts +19 -0
  32. package/lib/ngx-table.component.d.ts +37 -0
  33. package/lib/ngx-table.config.d.ts +45 -0
  34. package/lib/ngx-table.interface.d.ts +43 -0
  35. package/lib/views/action/view-action.component.d.ts +27 -0
  36. package/lib/views/card/toolbar/view-card-toolbar.component.d.ts +23 -0
  37. package/lib/views/card/view-card.component.d.ts +38 -0
  38. package/lib/views/index.d.ts +4 -0
  39. package/lib/views/pagination/view-pagination.component.d.ts +26 -0
  40. package/lib/views/table/view-table.component.d.ts +42 -0
  41. package/lib/views/value/view-value.component.d.ts +60 -0
  42. package/lib/views/view.interface.d.ts +41 -0
  43. package/lib/views/view.service.d.ts +30 -0
  44. package/package.json +47 -0
  45. package/public-api.d.ts +3 -0
@@ -0,0 +1,1258 @@
1
+ import * as i0 from '@angular/core';
2
+ import { InjectionToken, inject, Component, ViewChild, Injector, Injectable, Input, HostBinding, EventEmitter, Output, makeEnvironmentProviders, Optional, Inject } from '@angular/core';
3
+ import { NgClass, NgComponentOutlet, DecimalPipe } from '@angular/common';
4
+ import { Helper } from '@webilix/helper-library';
5
+ import { MatIcon } from '@angular/material/icon';
6
+ import * as i2 from '@webilix/ngx-helper-m3';
7
+ import { NGX_HELPER_CONTAINER_DATA, NGX_HELPER_CONTAINER_CLOSE, NgxHelperDatePipe, NgxHelperDurationPipe, NgxHelperMobilePipe, NgxHelperNumberPipe, NgxHelperMultiLinePipe } from '@webilix/ngx-helper-m3';
8
+ import { MatButton, MatIconButton } from '@angular/material/button';
9
+ import { NgxCalendarDateComponent } from '@webilix/ngx-calendar-m3';
10
+ import { JalaliDateTime } from '@webilix/jalali-date-time';
11
+ import { MatCheckbox } from '@angular/material/checkbox';
12
+ import * as i1 from '@angular/forms';
13
+ import { FormsModule } from '@angular/forms';
14
+ import { MatRadioButton, MatRadioGroup } from '@angular/material/radio';
15
+ import * as i1$1 from '@angular/router';
16
+ import { MatDivider } from '@angular/material/divider';
17
+ import * as i1$2 from '@angular/material/menu';
18
+ import { MatMenuModule } from '@angular/material/menu';
19
+ import * as i2$1 from '@angular/cdk/clipboard';
20
+ import { ClipboardModule } from '@angular/cdk/clipboard';
21
+ import { trigger, transition, style, animate } from '@angular/animations';
22
+
23
+ class FilterMethods {
24
+ }
25
+ const FILTER_DATA = new InjectionToken('NGX-TABLE-FILTER-DATA');
26
+ const FILTER_VALUE = new InjectionToken('NGX-TABLE-FILTER-VALUE');
27
+ const FILTER_CHANGE = new InjectionToken('NGX-TABLE-FILTER-CHANGE');
28
+
29
+ class FilterDateComponent {
30
+ data = inject(FILTER_DATA);
31
+ value = inject(FILTER_VALUE);
32
+ onChange = inject(FILTER_CHANGE);
33
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: FilterDateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
34
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.3", type: FilterDateComponent, isStandalone: true, selector: "ng-component", host: { attributes: { "selector": "filter-date" } }, ngImport: i0, template: "<ngx-calendar-date\n [value]=\"this.value\"\n [minDate]=\"this.data.filter.minDate\"\n [maxDate]=\"this.data.filter.maxDate\"\n (onChange)=\"onChange($event.date)\"\n></ngx-calendar-date>\n", styles: [""], dependencies: [{ kind: "component", type: NgxCalendarDateComponent, selector: "ngx-calendar-date", inputs: ["value", "minDate", "maxDate"], outputs: ["onChange"] }] });
35
+ }
36
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: FilterDateComponent, decorators: [{
37
+ type: Component,
38
+ args: [{ host: { selector: 'filter-date' }, imports: [NgxCalendarDateComponent], template: "<ngx-calendar-date\n [value]=\"this.value\"\n [minDate]=\"this.data.filter.minDate\"\n [maxDate]=\"this.data.filter.maxDate\"\n (onChange)=\"onChange($event.date)\"\n></ngx-calendar-date>\n" }]
39
+ }] });
40
+
41
+ class FilterDateMethods extends FilterMethods {
42
+ toParam(value) {
43
+ return value.toJSON();
44
+ }
45
+ value(value, filter) {
46
+ if (!value || !Helper.IS.STRING.date(value))
47
+ return undefined;
48
+ const jalali = JalaliDateTime();
49
+ const gregorian = jalali.gregorian(value).date;
50
+ const date = jalali.periodDay(1, new Date(`${gregorian}T00:00:00.000Z`)).from;
51
+ if (filter.minDate && date.getTime() < filter.minDate.getTime())
52
+ return undefined;
53
+ if (filter.maxDate && date.getTime() > filter.maxDate.getTime())
54
+ return undefined;
55
+ return date;
56
+ }
57
+ query(value) {
58
+ const jalali = JalaliDateTime();
59
+ return jalali.toString(value, { format: 'Y-M-D' });
60
+ }
61
+ active(value, filter) {
62
+ const jalali = JalaliDateTime();
63
+ return { value: jalali.toFullText(value, { format: 'Y/M/D' }), english: false };
64
+ }
65
+ }
66
+
67
+ class FilterMultiSelectComponent {
68
+ data = inject(FILTER_DATA);
69
+ value = inject(FILTER_VALUE);
70
+ onChange = inject(FILTER_CHANGE);
71
+ updateValue(id, checked) {
72
+ this.value = this.value || [];
73
+ if (!checked)
74
+ this.value = this.value.filter((v) => v !== id);
75
+ else if (!this.value.includes(id))
76
+ this.value.push(id);
77
+ this.onChange(this.value.length === 0 ? undefined : this.value);
78
+ }
79
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: FilterMultiSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
80
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.3", type: FilterMultiSelectComponent, isStandalone: true, selector: "ng-component", host: { attributes: { "selector": "filter-multi-select" } }, ngImport: i0, template: "@for (item of data.filter.options; track $index) {\n<mat-checkbox [checked]=\"(value || []).includes(item.id)\" (change)=\"updateValue(item.id, $event.checked)\">\n <div class=\"title\" [ngClass]=\"data.filter.english ? data.viewConfig.enClass : ''\">\n {{ item.title }}\n </div>\n</mat-checkbox>\n}\n", styles: ["mat-checkbox{display:block;padding:.5rem}mat-checkbox .title{cursor:pointer}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { 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"] }] });
81
+ }
82
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: FilterMultiSelectComponent, decorators: [{
83
+ type: Component,
84
+ args: [{ host: { selector: 'filter-multi-select' }, imports: [NgClass, MatCheckbox], template: "@for (item of data.filter.options; track $index) {\n<mat-checkbox [checked]=\"(value || []).includes(item.id)\" (change)=\"updateValue(item.id, $event.checked)\">\n <div class=\"title\" [ngClass]=\"data.filter.english ? data.viewConfig.enClass : ''\">\n {{ item.title }}\n </div>\n</mat-checkbox>\n}\n", styles: ["mat-checkbox{display:block;padding:.5rem}mat-checkbox .title{cursor:pointer}\n"] }]
85
+ }] });
86
+
87
+ class FilterMultiSelectMethods extends FilterMethods {
88
+ toParam(value) {
89
+ return value.join('||');
90
+ }
91
+ value(value, filter) {
92
+ if (!value || !Helper.IS.string(value))
93
+ return undefined;
94
+ const ids = filter.options.map((options) => options.id);
95
+ const values = value
96
+ .split('||')
97
+ .filter((item) => ids.includes(item))
98
+ .filter((item, index, arr) => arr.indexOf(item) === index);
99
+ return values.length === 0 ? undefined : values;
100
+ }
101
+ query(value) {
102
+ return this.toParam(value);
103
+ }
104
+ active(value, filter) {
105
+ const titles = value
106
+ .map((value) => filter.options.find((o) => o.id === value)?.title || '')
107
+ .filter((title) => title !== '');
108
+ const selected = titles.length > 2 ? `${value.length} گزینه` : titles.join(filter.english ? ', ' : '، ');
109
+ return { value: selected, english: !!filter.english };
110
+ }
111
+ }
112
+
113
+ class FilterSearchComponent {
114
+ searchInput;
115
+ data = inject(FILTER_DATA);
116
+ value = inject(FILTER_VALUE);
117
+ onChange = inject(FILTER_CHANGE);
118
+ query = this.value?.query;
119
+ mode = this.data.filter.mode || this.value?.mode || 'PHRASE';
120
+ ngAfterViewInit() {
121
+ if (!this.searchInput)
122
+ return;
123
+ const element = this.searchInput.nativeElement;
124
+ element?.focus();
125
+ }
126
+ updateQuery(query) {
127
+ query = query && Helper.IS.string(query) ? query.trim() : '';
128
+ this.query = query.length === 0 ? undefined : query;
129
+ this.onChange(this.query ? { query: this.query, mode: this.mode || 'PHRASE' } : undefined);
130
+ }
131
+ updateMode(mode) {
132
+ this.mode = mode;
133
+ this.onChange(this.query ? { query: this.query, mode: this.mode || 'PHRASE' } : undefined);
134
+ }
135
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: FilterSearchComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
136
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.3", type: FilterSearchComponent, isStandalone: true, selector: "ng-component", host: { attributes: { "selector": "filter-search" } }, viewQueries: [{ propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true }], ngImport: i0, template: "<div class=\"input\">\n <input\n [ngModel]=\"query || ''\"\n [ngClass]=\"data.filter.english ? data.viewConfig.enClass : ''\"\n [style.color]=\"data.viewConfig.inputText\"\n [style.background-color]=\"data.viewConfig.inputBackground\"\n [style.border-color]=\"data.viewConfig.borderColor\"\n [style.direction]=\"data.filter.english ? 'ltr' : 'rtl'\"\n (input)=\"updateQuery(searchInput.value)\"\n #searchInput\n />\n</div>\n\n@if (!data.filter.mode) {\n<mat-radio-group (change)=\"updateMode($event.value)\">\n <mat-radio-button [value]=\"'PHRASE'\" [checked]=\"mode === 'PHRASE'\">\n <div class=\"title\">\u0639\u0628\u0627\u0631\u062A \u06A9\u0627\u0645\u0644</div>\n </mat-radio-button>\n <mat-radio-button [value]=\"'ALL'\" [checked]=\"mode === 'ALL'\">\n <div class=\"title\">\u0647\u0645\u0647 \u06A9\u0644\u0645\u0627\u062A</div>\n </mat-radio-button>\n <mat-radio-button [value]=\"'EACH'\" [checked]=\"mode === 'EACH'\">\n <div class=\"title\">\u0647\u0631 \u06A9\u062F\u0627\u0645 \u0627\u0632 \u06A9\u0644\u0645\u0627\u062A</div>\n </mat-radio-button>\n</mat-radio-group>\n}\n", styles: [".input{display:flex;margin:1rem}.input input{padding:.75rem .5rem;border-radius:8px;border-width:0;border-bottom:1px solid transparent;outline:none;width:100%}mat-radio-group{display:flex;flex-direction:column;padding-bottom:1rem}mat-radio-group mat-radio-button{padding:0 .5rem;border-top:1px solid transparent}mat-radio-group mat-radio-button .title{cursor:pointer}mat-radio-group mat-radio-button:first-of-type{border-top-width:0}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { 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.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: MatRadioButton, selector: "mat-radio-button", inputs: ["id", "name", "aria-label", "aria-labelledby", "aria-describedby", "disableRipple", "tabIndex", "checked", "value", "labelPosition", "disabled", "required", "color", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioButton"] }, { kind: "directive", type: MatRadioGroup, selector: "mat-radio-group", inputs: ["color", "name", "labelPosition", "value", "selected", "disabled", "required", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioGroup"] }] });
137
+ }
138
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: FilterSearchComponent, decorators: [{
139
+ type: Component,
140
+ args: [{ host: { selector: 'filter-search' }, imports: [NgClass, FormsModule, MatRadioButton, MatRadioGroup], template: "<div class=\"input\">\n <input\n [ngModel]=\"query || ''\"\n [ngClass]=\"data.filter.english ? data.viewConfig.enClass : ''\"\n [style.color]=\"data.viewConfig.inputText\"\n [style.background-color]=\"data.viewConfig.inputBackground\"\n [style.border-color]=\"data.viewConfig.borderColor\"\n [style.direction]=\"data.filter.english ? 'ltr' : 'rtl'\"\n (input)=\"updateQuery(searchInput.value)\"\n #searchInput\n />\n</div>\n\n@if (!data.filter.mode) {\n<mat-radio-group (change)=\"updateMode($event.value)\">\n <mat-radio-button [value]=\"'PHRASE'\" [checked]=\"mode === 'PHRASE'\">\n <div class=\"title\">\u0639\u0628\u0627\u0631\u062A \u06A9\u0627\u0645\u0644</div>\n </mat-radio-button>\n <mat-radio-button [value]=\"'ALL'\" [checked]=\"mode === 'ALL'\">\n <div class=\"title\">\u0647\u0645\u0647 \u06A9\u0644\u0645\u0627\u062A</div>\n </mat-radio-button>\n <mat-radio-button [value]=\"'EACH'\" [checked]=\"mode === 'EACH'\">\n <div class=\"title\">\u0647\u0631 \u06A9\u062F\u0627\u0645 \u0627\u0632 \u06A9\u0644\u0645\u0627\u062A</div>\n </mat-radio-button>\n</mat-radio-group>\n}\n", styles: [".input{display:flex;margin:1rem}.input input{padding:.75rem .5rem;border-radius:8px;border-width:0;border-bottom:1px solid transparent;outline:none;width:100%}mat-radio-group{display:flex;flex-direction:column;padding-bottom:1rem}mat-radio-group mat-radio-button{padding:0 .5rem;border-top:1px solid transparent}mat-radio-group mat-radio-button .title{cursor:pointer}mat-radio-group mat-radio-button:first-of-type{border-top-width:0}\n"] }]
141
+ }], propDecorators: { searchInput: [{
142
+ type: ViewChild,
143
+ args: ['searchInput']
144
+ }] } });
145
+
146
+ class FilterSearchMethods extends FilterMethods {
147
+ toParam(value) {
148
+ return `${value.query}:${value.mode}`;
149
+ }
150
+ value(value, filter) {
151
+ if (!value || !Helper.IS.string(value))
152
+ return undefined;
153
+ const index = value.lastIndexOf(':');
154
+ if (index === -1)
155
+ return undefined;
156
+ const query = value.substring(0, index);
157
+ if (!query || !Helper.IS.string(query))
158
+ return undefined;
159
+ const mode = value.substring(index + 1);
160
+ if (!['PHRASE', 'EACH', 'ALL'].includes(mode))
161
+ return undefined;
162
+ if (filter.mode && filter.mode !== mode)
163
+ return undefined;
164
+ return { query, mode };
165
+ }
166
+ query(value) {
167
+ return this.toParam(value);
168
+ }
169
+ active(value, filter) {
170
+ return { value: value.query, english: !!filter.english };
171
+ }
172
+ }
173
+
174
+ class FilterSelectComponent {
175
+ data = inject(FILTER_DATA);
176
+ value = inject(FILTER_VALUE);
177
+ onChange = inject(FILTER_CHANGE);
178
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: FilterSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
179
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.3", type: FilterSelectComponent, isStandalone: true, selector: "ng-component", host: { attributes: { "selector": "filter-select" } }, ngImport: i0, template: "<mat-radio-group (change)=\"onChange($event.value)\">\n @for (item of data.filter.options; track $index) {\n <mat-radio-button [value]=\"item.id\" [checked]=\"item.id === value\">\n <div class=\"title\" [ngClass]=\"data.filter.english ? data.viewConfig.enClass : ''\">\n {{ item.title }}\n </div>\n </mat-radio-button>\n }\n</mat-radio-group>\n", styles: [":host{display:block;padding:.5rem}mat-radio-group{display:flex;flex-direction:column}mat-radio-group mat-radio-button .title{cursor:pointer}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: MatRadioButton, selector: "mat-radio-button", inputs: ["id", "name", "aria-label", "aria-labelledby", "aria-describedby", "disableRipple", "tabIndex", "checked", "value", "labelPosition", "disabled", "required", "color", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioButton"] }, { kind: "directive", type: MatRadioGroup, selector: "mat-radio-group", inputs: ["color", "name", "labelPosition", "value", "selected", "disabled", "required", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioGroup"] }] });
180
+ }
181
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: FilterSelectComponent, decorators: [{
182
+ type: Component,
183
+ args: [{ host: { selector: 'filter-select' }, imports: [NgClass, MatRadioButton, MatRadioGroup], template: "<mat-radio-group (change)=\"onChange($event.value)\">\n @for (item of data.filter.options; track $index) {\n <mat-radio-button [value]=\"item.id\" [checked]=\"item.id === value\">\n <div class=\"title\" [ngClass]=\"data.filter.english ? data.viewConfig.enClass : ''\">\n {{ item.title }}\n </div>\n </mat-radio-button>\n }\n</mat-radio-group>\n", styles: [":host{display:block;padding:.5rem}mat-radio-group{display:flex;flex-direction:column}mat-radio-group mat-radio-button .title{cursor:pointer}\n"] }]
184
+ }] });
185
+
186
+ class FilterSelectMethods extends FilterMethods {
187
+ toParam(value) {
188
+ return value;
189
+ }
190
+ value(value, filter) {
191
+ if (!value || !Helper.IS.string(value))
192
+ return undefined;
193
+ const ids = filter.options.map((options) => options.id);
194
+ return ids.includes(value) ? value : undefined;
195
+ }
196
+ query(value) {
197
+ return this.toParam(value);
198
+ }
199
+ active(value, filter) {
200
+ return { value: filter.options.find((o) => o.id === value)?.title || '', english: !!filter.english };
201
+ }
202
+ }
203
+
204
+ const FilterInfo = {
205
+ DATE: { methods: new FilterDateMethods(), component: FilterDateComponent },
206
+ 'MULTI-SELECT': { methods: new FilterMultiSelectMethods(), component: FilterMultiSelectComponent },
207
+ SEARCH: { methods: new FilterSearchMethods(), component: FilterSearchComponent },
208
+ SELECT: { methods: new FilterSelectMethods(), component: FilterSelectComponent },
209
+ };
210
+
211
+ class FilterComponent {
212
+ data = inject(NGX_HELPER_CONTAINER_DATA);
213
+ closeContainer = inject(NGX_HELPER_CONTAINER_CLOSE);
214
+ filterInfo = FilterInfo;
215
+ value = undefined;
216
+ injector;
217
+ ngOnInit() {
218
+ this.value = this.data.filter.value;
219
+ this.injector = Injector.create({
220
+ providers: [
221
+ { provide: FILTER_DATA, useValue: { filter: this.data.filter.filter, viewConfig: this.data.viewConfig } },
222
+ { provide: FILTER_VALUE, useValue: this.value },
223
+ { provide: FILTER_CHANGE, useFactory: () => (value) => (this.value = value) },
224
+ ],
225
+ });
226
+ }
227
+ onKeydown(event) {
228
+ if (!(event instanceof KeyboardEvent))
229
+ return;
230
+ if (event.code === 'Enter' && this.value)
231
+ this.closeContainer({ value: this.value });
232
+ }
233
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: FilterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
234
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.3", type: FilterComponent, isStandalone: true, selector: "filter", host: { listeners: { "window:keydown": "onKeydown($event)" } }, ngImport: i0, template: "<content>\n <ng-container *ngComponentOutlet=\"filterInfo[data.filter.filter.type].component; injector: injector\"></ng-container>\n</content>\n\n<footer>\n <button mat-stroked-button type=\"button\" [disabled]=\"!value\" (click)=\"closeContainer({ value: undefined })\">\n \u0644\u063A\u0648 \u0641\u06CC\u0644\u062A\u0631\n </button>\n <button mat-flat-button type=\"button\" class=\"confirm\" [disabled]=\"!value\" (click)=\"closeContainer({value})\">\n \u062A\u0627\u06CC\u06CC\u062F\n </button>\n</footer>\n", styles: [":host{display:flex;flex-direction:column}:host content{display:block;overflow-x:hidden;overflow-y:auto;max-height:60vh}:host footer{display:flex;justify-content:flex-end;padding:1rem;column-gap:.5rem;border-top:1px solid var(--surface-container-highest)}:host footer button.confirm{flex:1}\n"], dependencies: [{ kind: "component", type: MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"] }] });
235
+ }
236
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: FilterComponent, decorators: [{
237
+ type: Component,
238
+ args: [{ selector: 'filter', host: { '(window:keydown)': 'onKeydown($event)' }, imports: [MatButton, NgComponentOutlet], template: "<content>\n <ng-container *ngComponentOutlet=\"filterInfo[data.filter.filter.type].component; injector: injector\"></ng-container>\n</content>\n\n<footer>\n <button mat-stroked-button type=\"button\" [disabled]=\"!value\" (click)=\"closeContainer({ value: undefined })\">\n \u0644\u063A\u0648 \u0641\u06CC\u0644\u062A\u0631\n </button>\n <button mat-flat-button type=\"button\" class=\"confirm\" [disabled]=\"!value\" (click)=\"closeContainer({value})\">\n \u062A\u0627\u06CC\u06CC\u062F\n </button>\n</footer>\n", styles: [":host{display:flex;flex-direction:column}:host content{display:block;overflow-x:hidden;overflow-y:auto;max-height:60vh}:host footer{display:flex;justify-content:flex-end;padding:1rem;column-gap:.5rem;border-top:1px solid var(--surface-container-highest)}:host footer button.confirm{flex:1}\n"] }]
239
+ }] });
240
+
241
+ class FilterService {
242
+ activatedRoute;
243
+ ngxHelperContainerService;
244
+ constructor(activatedRoute, ngxHelperContainerService) {
245
+ this.activatedRoute = activatedRoute;
246
+ this.ngxHelperContainerService = ngxHelperContainerService;
247
+ }
248
+ getFilters(ngxTable) {
249
+ const filters = {};
250
+ // CHECK COLUMNS
251
+ ngxTable.columns.forEach((column) => {
252
+ if (!column.tools || !('filter' in column.tools) || !column.tools.filter)
253
+ return;
254
+ const title = column.title || '';
255
+ const key = column.tools.id;
256
+ filters[key] = { title, filter: column.tools.filter };
257
+ });
258
+ if (Object.keys(filters).length === 0)
259
+ return {};
260
+ // CHECK QUERY PARAMS
261
+ const queryParams = { ...this.activatedRoute.snapshot.queryParams };
262
+ Object.keys(filters).forEach((id) => {
263
+ const param = queryParams[`ngx-table-filter-${id}`];
264
+ if (!param || !Helper.IS.string(param))
265
+ return;
266
+ const column = ngxTable.columns.find((column) => column.tools?.id === id);
267
+ if (!column || !column.tools || !('filter' in column.tools) || !column.tools.filter)
268
+ return;
269
+ const value = FilterInfo[column.tools.filter.type].methods.value(param, column.tools.filter);
270
+ filters[id] = { ...filters[id], value };
271
+ });
272
+ return filters;
273
+ }
274
+ updateFilter(filter, viewConfig) {
275
+ return new Promise((resolve) => {
276
+ this.ngxHelperContainerService
277
+ .init(FilterComponent, filter.title, { data: { filter, viewConfig }, padding: '0' })
278
+ .bottomSheet((response) => resolve({ ...filter, value: response.value }), () => resolve(undefined));
279
+ });
280
+ }
281
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: FilterService, deps: [{ token: i1$1.ActivatedRoute }, { token: i2.NgxHelperContainerService }], target: i0.ɵɵFactoryTarget.Injectable });
282
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: FilterService });
283
+ }
284
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: FilterService, decorators: [{
285
+ type: Injectable
286
+ }], ctorParameters: () => [{ type: i1$1.ActivatedRoute }, { type: i2.NgxHelperContainerService }] });
287
+
288
+ class ViewActionComponent {
289
+ router;
290
+ actions;
291
+ item;
292
+ viewConfig;
293
+ isMobile;
294
+ inRow = [];
295
+ inMenu = [];
296
+ constructor(router) {
297
+ this.router = router;
298
+ }
299
+ ngOnChanges(changes) {
300
+ this.inRow = [];
301
+ this.inMenu = [];
302
+ this.actions.forEach((action) => {
303
+ if (action === 'DIVIDER') {
304
+ if (this.inMenu.length === 0)
305
+ return;
306
+ if (this.inMenu[this.inMenu.length - 1] === 'DIVIDER')
307
+ return;
308
+ this.inMenu.push('DIVIDER');
309
+ return;
310
+ }
311
+ if (action.hideOn && action.hideOn(this.item))
312
+ return;
313
+ let item = undefined;
314
+ const isDisabled = !!action.disableOn && action.disableOn(this.item);
315
+ const color = action.standalone ? this.viewConfig.actionButtonColor : this.viewConfig.actionMenuColor;
316
+ switch (action.type) {
317
+ case 'ACTION':
318
+ item = {
319
+ title: action.title,
320
+ icon: action.icon,
321
+ action: action.action,
322
+ color: action.color || color,
323
+ isDisabled,
324
+ };
325
+ break;
326
+ case 'UPDATE':
327
+ item = { title: 'ویرایش', icon: 'edit', color, action: action.action, isDisabled };
328
+ break;
329
+ case 'DELETE':
330
+ item = {
331
+ title: 'حذف',
332
+ icon: 'delete',
333
+ color: this.viewConfig.actionWarnColor,
334
+ action: action.action,
335
+ isDisabled,
336
+ };
337
+ break;
338
+ case 'STATUS':
339
+ const isDeactive = action.isDeactive(this.item);
340
+ item = {
341
+ title: isDeactive ? 'فعال کردن' : 'غیرفعال کردن',
342
+ icon: isDeactive ? 'check_box' : 'disabled_by_default',
343
+ color: isDeactive ? color : this.viewConfig.actionWarnColor,
344
+ action: (data) => action.action(data, isDeactive),
345
+ isDisabled,
346
+ };
347
+ break;
348
+ case 'LOG':
349
+ item = {
350
+ title: 'گزارش تغییرات',
351
+ icon: 'published_with_changes',
352
+ color,
353
+ action: action.action,
354
+ isDisabled,
355
+ };
356
+ break;
357
+ }
358
+ if (!item)
359
+ return;
360
+ action.standalone ? this.inRow.push(item) : this.inMenu.push(item);
361
+ });
362
+ while (this.inMenu[this.inMenu.length - 1] === 'DIVIDER')
363
+ this.inMenu.splice(this.inMenu.length - 1, 1);
364
+ }
365
+ onClick(action) {
366
+ const result = action(this.item);
367
+ if (result)
368
+ this.router.navigate(result);
369
+ }
370
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: ViewActionComponent, deps: [{ token: i1$1.Router }], target: i0.ɵɵFactoryTarget.Component });
371
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.3", type: ViewActionComponent, isStandalone: true, selector: "view-action", inputs: { actions: "actions", item: "item", viewConfig: "viewConfig", isMobile: "isMobile" }, usesOnChanges: true, ngImport: i0, template: "<!-- ROW -->\n@for (item of inRow; track $index) {\n<!-- DESKTOP -->\n@if (!isMobile) {\n<button\n mat-button\n type=\"button\"\n [style.color]=\"item.isDisabled ? '' : item.color\"\n [style.font-size]=\"viewConfig.actionButtonSize\"\n [disabled]=\"item.isDisabled\"\n (click)=\"onClick(item.action)\"\n class=\"desktop\"\n>\n {{ item.title }}\n</button>\n}\n<!-- MOBILE -->\n@else {\n<button mat-icon-button type=\"button\" [disabled]=\"item.isDisabled\" (click)=\"onClick(item.action)\">\n <mat-icon [style.color]=\"item.isDisabled ? '' : item.color\">{{ item.icon }}</mat-icon>\n</button>\n} }\n\n<!-- MENU -->\n@if (this.inMenu.length > 0) {\n<!-- DESKTOP -->\n@if (!isMobile) {\n<button\n mat-button\n type=\"button\"\n [matMenuTriggerFor]=\"actionMenu\"\n [style.color]=\"viewConfig.actionButtonColor\"\n [style.font-size]=\"viewConfig.actionButtonSize\"\n class=\"desktop\"\n>\n {{ viewConfig.actionMenuTitle }}\n</button>\n}\n<!-- MOBILE -->\n@else {\n<button mat-icon-button type=\"button\" [matMenuTriggerFor]=\"actionMenu\">\n <mat-icon [style.color]=\"viewConfig.actionButtonColor\">more_vert</mat-icon>\n</button>\n}\n\n<mat-menu #actionMenu=\"matMenu\" [xPosition]=\"'after'\" class=\"ngx-helper-action-menu\">\n @for (item of inMenu; track $index) {\n <!-- DIVIDER -->\n @if (item === 'DIVIDER') {\n <mat-divider></mat-divider>\n }\n\n <!-- MENU ITEM -->\n @else {\n <button\n mat-menu-item\n type=\"button\"\n [style.color]=\"item.isDisabled ? '' : item.color\"\n (click)=\"onClick(item.action)\"\n [disabled]=\"item.isDisabled\"\n >\n <span>{{ item.title }}</span>\n <mat-icon [style.color]=\"item.isDisabled ? '' : item.color\">{{ item.icon }}</mat-icon>\n </button>\n } }\n</mat-menu>\n}\n", styles: [":host{display:flex;align-items:center;justify-content:flex-end}:host button.desktop{border-radius:0;z-index:0}::ng-deep .ngx-helper-action-menu mat-icon{margin:0 0 0 .75rem!important}::ng-deep .ngx-helper-action-menu .mat-mdc-menu-content{padding:0}::ng-deep .ngx-helper-action-menu .mat-mdc-menu-item{direction:rtl;text-align:right}::ng-deep .ngx-helper-action-menu .mat-divider{margin:0;border-top-color:var(--outline-variant)}\n"], dependencies: [{ kind: "component", type: MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "component", type: MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i1$2.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: i1$2.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i1$2.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }] });
372
+ }
373
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: ViewActionComponent, decorators: [{
374
+ type: Component,
375
+ args: [{ selector: 'view-action', imports: [MatButton, MatDivider, MatIconButton, MatIcon, MatMenuModule], template: "<!-- ROW -->\n@for (item of inRow; track $index) {\n<!-- DESKTOP -->\n@if (!isMobile) {\n<button\n mat-button\n type=\"button\"\n [style.color]=\"item.isDisabled ? '' : item.color\"\n [style.font-size]=\"viewConfig.actionButtonSize\"\n [disabled]=\"item.isDisabled\"\n (click)=\"onClick(item.action)\"\n class=\"desktop\"\n>\n {{ item.title }}\n</button>\n}\n<!-- MOBILE -->\n@else {\n<button mat-icon-button type=\"button\" [disabled]=\"item.isDisabled\" (click)=\"onClick(item.action)\">\n <mat-icon [style.color]=\"item.isDisabled ? '' : item.color\">{{ item.icon }}</mat-icon>\n</button>\n} }\n\n<!-- MENU -->\n@if (this.inMenu.length > 0) {\n<!-- DESKTOP -->\n@if (!isMobile) {\n<button\n mat-button\n type=\"button\"\n [matMenuTriggerFor]=\"actionMenu\"\n [style.color]=\"viewConfig.actionButtonColor\"\n [style.font-size]=\"viewConfig.actionButtonSize\"\n class=\"desktop\"\n>\n {{ viewConfig.actionMenuTitle }}\n</button>\n}\n<!-- MOBILE -->\n@else {\n<button mat-icon-button type=\"button\" [matMenuTriggerFor]=\"actionMenu\">\n <mat-icon [style.color]=\"viewConfig.actionButtonColor\">more_vert</mat-icon>\n</button>\n}\n\n<mat-menu #actionMenu=\"matMenu\" [xPosition]=\"'after'\" class=\"ngx-helper-action-menu\">\n @for (item of inMenu; track $index) {\n <!-- DIVIDER -->\n @if (item === 'DIVIDER') {\n <mat-divider></mat-divider>\n }\n\n <!-- MENU ITEM -->\n @else {\n <button\n mat-menu-item\n type=\"button\"\n [style.color]=\"item.isDisabled ? '' : item.color\"\n (click)=\"onClick(item.action)\"\n [disabled]=\"item.isDisabled\"\n >\n <span>{{ item.title }}</span>\n <mat-icon [style.color]=\"item.isDisabled ? '' : item.color\">{{ item.icon }}</mat-icon>\n </button>\n } }\n</mat-menu>\n}\n", styles: [":host{display:flex;align-items:center;justify-content:flex-end}:host button.desktop{border-radius:0;z-index:0}::ng-deep .ngx-helper-action-menu mat-icon{margin:0 0 0 .75rem!important}::ng-deep .ngx-helper-action-menu .mat-mdc-menu-content{padding:0}::ng-deep .ngx-helper-action-menu .mat-mdc-menu-item{direction:rtl;text-align:right}::ng-deep .ngx-helper-action-menu .mat-divider{margin:0;border-top-color:var(--outline-variant)}\n"] }]
376
+ }], ctorParameters: () => [{ type: i1$1.Router }], propDecorators: { actions: [{
377
+ type: Input,
378
+ args: [{ required: true }]
379
+ }], item: [{
380
+ type: Input,
381
+ args: [{ required: true }]
382
+ }], viewConfig: [{
383
+ type: Input,
384
+ args: [{ required: true }]
385
+ }], isMobile: [{
386
+ type: Input,
387
+ args: [{ required: true }]
388
+ }] } });
389
+
390
+ class ColumnMethods {
391
+ }
392
+ const COLUMN_TYPE = new InjectionToken('NGX-TABLE-COLUMN-TYPE');
393
+ const COLUMN_CONFIG = new InjectionToken('NGX-TABLE-COLUMN-CONFIG');
394
+ const COLUMN_VALUE = new InjectionToken('NGX-TABLE-COLUMN-VALUE');
395
+
396
+ class ColumnDateComponent {
397
+ column = inject(COLUMN_TYPE);
398
+ value = inject(COLUMN_VALUE);
399
+ config = inject(COLUMN_CONFIG);
400
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: ColumnDateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
401
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.3", type: ColumnDateComponent, isStandalone: true, selector: "ng-component", host: { attributes: { "selector": "column-date" } }, ngImport: i0, template: "<div [style.display]=\"'inline-block'\" [ngClass]=\"[config.isDeactive ? config.deactiveClass : '']\">\n {{ value | ngxHelperDate : { format: column.format } }}\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: NgxHelperDatePipe, name: "ngxHelperDate" }] });
402
+ }
403
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: ColumnDateComponent, decorators: [{
404
+ type: Component,
405
+ args: [{ host: { selector: 'column-date' }, imports: [NgClass, NgxHelperDatePipe], template: "<div [style.display]=\"'inline-block'\" [ngClass]=\"[config.isDeactive ? config.deactiveClass : '']\">\n {{ value | ngxHelperDate : { format: column.format } }}\n</div>\n" }]
406
+ }] });
407
+
408
+ class ColumnDateMethods extends ColumnMethods {
409
+ column(column) {
410
+ return { ...column, title: column.title || 'تاریخ' };
411
+ }
412
+ value(value, column) {
413
+ return Helper.IS.date(value) ? value : undefined;
414
+ }
415
+ }
416
+
417
+ class ColumnDurationComponent {
418
+ column = inject(COLUMN_TYPE);
419
+ value = inject(COLUMN_VALUE);
420
+ config = inject(COLUMN_CONFIG);
421
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: ColumnDurationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
422
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.3", type: ColumnDurationComponent, isStandalone: true, selector: "ng-component", host: { attributes: { "selector": "column-duration" } }, ngImport: i0, template: "<div\n [style.display]=\"'inline-block'\"\n [ngClass]=\"[config.isEN ? config.enClass : '', config.isDeactive ? config.deactiveClass : '']\"\n>\n {{ value | ngxHelperDuration : { english: config.isEN, format: column.format } }}\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: NgxHelperDurationPipe, name: "ngxHelperDuration" }] });
423
+ }
424
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: ColumnDurationComponent, decorators: [{
425
+ type: Component,
426
+ args: [{ host: { selector: 'column-duration' }, imports: [NgClass, NgxHelperDurationPipe], template: "<div\n [style.display]=\"'inline-block'\"\n [ngClass]=\"[config.isEN ? config.enClass : '', config.isDeactive ? config.deactiveClass : '']\"\n>\n {{ value | ngxHelperDuration : { english: config.isEN, format: column.format } }}\n</div>\n" }]
427
+ }] });
428
+
429
+ class ColumnDurationMethods extends ColumnMethods {
430
+ column(column) {
431
+ return { ...column };
432
+ }
433
+ value(value, column) {
434
+ if (Helper.IS.number(value))
435
+ return Math.abs(value);
436
+ else if (Helper.IS.date(value))
437
+ return Math.floor(Math.abs(new Date().getTime() - value.getTime()) / 1000);
438
+ else if (Helper.IS.object(value)) {
439
+ const from = Helper.IS.date(value?.from) ? value.from : undefined;
440
+ const to = Helper.IS.date(value?.to) ? value.to : undefined;
441
+ if (!from && !to)
442
+ return undefined;
443
+ return Math.floor(Math.abs((from || new Date()).getTime() - (to || new Date()).getTime()) / 1000);
444
+ }
445
+ return undefined;
446
+ }
447
+ }
448
+
449
+ class ColumnMobileComponent {
450
+ column = inject(COLUMN_TYPE);
451
+ value = inject(COLUMN_VALUE);
452
+ config = inject(COLUMN_CONFIG);
453
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: ColumnMobileComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
454
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.3", type: ColumnMobileComponent, isStandalone: true, selector: "ng-component", host: { attributes: { "selector": "column-mobile" } }, ngImport: i0, template: "<div\n [style.display]=\"'inline-block'\"\n [ngClass]=\"[config.isEN ? config.enClass : '', config.isDeactive ? config.deactiveClass : '']\"\n>\n {{ value | ngxHelperMobile }}\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: NgxHelperMobilePipe, name: "ngxHelperMobile" }] });
455
+ }
456
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: ColumnMobileComponent, decorators: [{
457
+ type: Component,
458
+ args: [{ host: { selector: 'column-mobile' }, imports: [NgClass, NgxHelperMobilePipe], template: "<div\n [style.display]=\"'inline-block'\"\n [ngClass]=\"[config.isEN ? config.enClass : '', config.isDeactive ? config.deactiveClass : '']\"\n>\n {{ value | ngxHelperMobile }}\n</div>\n" }]
459
+ }] });
460
+
461
+ class ColumnMobileMethods extends ColumnMethods {
462
+ column(column) {
463
+ return { ...column, title: column.title || 'موبایل' };
464
+ }
465
+ value(value, column) {
466
+ return Helper.IS.STRING.mobile(value) ? value : undefined;
467
+ }
468
+ }
469
+
470
+ class ColumnNumberComponent {
471
+ column = inject(COLUMN_TYPE);
472
+ value = inject(COLUMN_VALUE);
473
+ config = inject(COLUMN_CONFIG);
474
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: ColumnNumberComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
475
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.3", type: ColumnNumberComponent, isStandalone: true, selector: "ng-component", host: { attributes: { "selector": "column-number" } }, ngImport: i0, template: "<div\n [style.display]=\"'inline-block'\"\n [dir]=\"'ltr'\"\n [ngClass]=\"[config.isEN ? config.enClass : '', config.isDeactive ? config.deactiveClass : '']\"\n>\n {{ value | ngxHelperNumber : { english: config.isEN, fractionDigits: column.fractionDigits } }}\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: NgxHelperNumberPipe, name: "ngxHelperNumber" }] });
476
+ }
477
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: ColumnNumberComponent, decorators: [{
478
+ type: Component,
479
+ args: [{ host: { selector: 'column-number' }, imports: [NgClass, NgxHelperNumberPipe], template: "<div\n [style.display]=\"'inline-block'\"\n [dir]=\"'ltr'\"\n [ngClass]=\"[config.isEN ? config.enClass : '', config.isDeactive ? config.deactiveClass : '']\"\n>\n {{ value | ngxHelperNumber : { english: config.isEN, fractionDigits: column.fractionDigits } }}\n</div>\n" }]
480
+ }] });
481
+
482
+ class ColumnNumberMethods extends ColumnMethods {
483
+ column(column) {
484
+ return { ...column };
485
+ }
486
+ value(value, column) {
487
+ return Helper.IS.number(value) ? value : undefined;
488
+ }
489
+ }
490
+
491
+ class ColumnTextComponent {
492
+ column = inject(COLUMN_TYPE);
493
+ value = inject(COLUMN_VALUE);
494
+ config = inject(COLUMN_CONFIG);
495
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: ColumnTextComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
496
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.3", type: ColumnTextComponent, isStandalone: true, selector: "ng-component", host: { attributes: { "selector": "column-text" } }, ngImport: i0, template: "<div\n [style.display]=\"'inline-block'\"\n [ngClass]=\"[config.isEN ? config.enClass : '', config.isDeactive ? config.deactiveClass : '']\"\n>\n {{ value }}\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
497
+ }
498
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: ColumnTextComponent, decorators: [{
499
+ type: Component,
500
+ args: [{ host: { selector: 'column-text' }, imports: [NgClass], template: "<div\n [style.display]=\"'inline-block'\"\n [ngClass]=\"[config.isEN ? config.enClass : '', config.isDeactive ? config.deactiveClass : '']\"\n>\n {{ value }}\n</div>\n" }]
501
+ }] });
502
+
503
+ class ColumnTextMethods extends ColumnMethods {
504
+ column(column) {
505
+ return { ...column };
506
+ }
507
+ value(value, column) {
508
+ return Helper.IS.string(value) && value !== '' ? value : undefined;
509
+ }
510
+ }
511
+
512
+ const ColumnInfo = {
513
+ DATE: { methods: new ColumnDateMethods(), component: ColumnDateComponent },
514
+ DURATION: { methods: new ColumnDurationMethods(), component: ColumnDurationComponent },
515
+ MOBILE: { methods: new ColumnMobileMethods(), component: ColumnMobileComponent },
516
+ NUMBER: { methods: new ColumnNumberMethods(), component: ColumnNumberComponent },
517
+ TEXT: { methods: new ColumnTextMethods(), component: ColumnTextComponent },
518
+ };
519
+
520
+ class ViewValueComponent {
521
+ router;
522
+ textAlign = 'left';
523
+ column;
524
+ item;
525
+ viewConfig;
526
+ isDeactive;
527
+ isCard;
528
+ isCardTitle;
529
+ isCardSubTitle;
530
+ columnInfo = ColumnInfo;
531
+ injector;
532
+ value;
533
+ subValue;
534
+ color;
535
+ hasClick;
536
+ copyText;
537
+ isCopied = false;
538
+ copyTimeout;
539
+ constructor(router) {
540
+ this.router = router;
541
+ }
542
+ ngOnChanges(changes) {
543
+ this.textAlign = this.isCard ? 'right' : (this.column.textAlign || 'RIGHT').toLocaleLowerCase();
544
+ this.value = this.getValue();
545
+ this.subValue = this.getSubValue();
546
+ this.color = this.column.color
547
+ ? typeof this.column.color === 'function'
548
+ ? this.column.color(this.item)
549
+ : this.column.color
550
+ : undefined;
551
+ this.hasClick = !!this.column.onClick;
552
+ this.copyText = !this.hasClick && this.column.onCopy ? this.column.onCopy(this.item) : undefined;
553
+ const columnConfig = {
554
+ isEN: 'english' in this.column && this.column.english
555
+ ? typeof this.column.english === 'function'
556
+ ? this.column.english(this.item)
557
+ : this.column.english
558
+ : false,
559
+ enClass: this.viewConfig.enClass,
560
+ isDeactive: !!this.isDeactive,
561
+ deactiveClass: this.viewConfig.deactiveClass,
562
+ };
563
+ this.injector = Injector.create({
564
+ providers: [
565
+ { provide: COLUMN_TYPE, useValue: this.column },
566
+ { provide: COLUMN_VALUE, useValue: this.value },
567
+ { provide: COLUMN_CONFIG, useValue: columnConfig },
568
+ ],
569
+ });
570
+ }
571
+ getValue() {
572
+ const value = typeof this.column.value === 'function' ? this.column.value(this.item) : this.item[this.column.value];
573
+ if (Helper.IS.empty(value))
574
+ return undefined;
575
+ return ColumnInfo[this.column.type].methods.value(value, this.column);
576
+ }
577
+ getSubValue() {
578
+ if (!this.column.subValue)
579
+ return undefined;
580
+ if (typeof this.column.subValue === 'function') {
581
+ const subValue = this.column.subValue(this.item);
582
+ if (subValue === undefined || Helper.IS.empty(subValue))
583
+ return undefined;
584
+ return {
585
+ value: typeof subValue === 'string' ? subValue : subValue.value,
586
+ isEN: typeof subValue === 'string' ? false : !!subValue.english,
587
+ };
588
+ }
589
+ else {
590
+ const subValue = this.item[this.column.subValue];
591
+ if (Helper.IS.empty(subValue))
592
+ return undefined;
593
+ return { value: subValue, isEN: false };
594
+ }
595
+ }
596
+ onClick() {
597
+ if (!this.column.onClick)
598
+ return;
599
+ const onClick = this.column.onClick(this.item);
600
+ if (typeof onClick === 'function')
601
+ onClick();
602
+ else
603
+ this.router.navigate(onClick);
604
+ }
605
+ onCopy() {
606
+ if (!this.copyText)
607
+ return;
608
+ if (this.copyTimeout)
609
+ clearTimeout(this.copyTimeout);
610
+ this.isCopied = true;
611
+ this.copyTimeout = setTimeout(() => {
612
+ this.isCopied = false;
613
+ this.copyTimeout = undefined;
614
+ }, 2000);
615
+ }
616
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: ViewValueComponent, deps: [{ token: i1$1.Router }], target: i0.ɵɵFactoryTarget.Component });
617
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.3", type: ViewValueComponent, isStandalone: true, selector: "view-value", inputs: { column: "column", item: "item", viewConfig: "viewConfig", isDeactive: "isDeactive", isCard: "isCard", isCardTitle: "isCardTitle", isCardSubTitle: "isCardSubTitle" }, host: { properties: { "style.text-align": "this.textAlign" } }, usesOnChanges: true, ngImport: i0, template: "<!-- EMPTY VALUE -->\n@if (value === undefined) { }\n\n<!-- SHOW VALUE -->\n@else {\n<div [style.color]=\"color\" [class.card-title]=\"isCardTitle\" [class.card-sub-title]=\"isCardSubTitle\">\n <div\n class=\"value\"\n [style.cursor]=\"hasClick || copyText ? 'pointer' : 'default'\"\n (click)=\"hasClick ? onClick() : copyText ? onCopy() : null\"\n [cdkCopyToClipboard]=\"copyText || ''\"\n >\n <ng-container *ngComponentOutlet=\"columnInfo[column.type].component; injector: injector\"></ng-container>\n <!-- CLICK -->\n @if (hasClick) { <mat-icon>open_in_new</mat-icon> }\n <!-- COPY -->\n @if (copyText) { <mat-icon>{{ isCopied ? 'done_all' : 'copy' }}</mat-icon> }\n </div>\n\n <!-- SUB VALUE -->\n @if (subValue) {\n <div class=\"subvalue\" [ngClass]=\"[subValue.isEN ? viewConfig.enClass : '']\">{{ subValue.value }}</div>\n }\n</div>\n}\n", styles: [".value{display:inline-flex;align-items:center}.value mat-icon{font-size:100%;padding:0 .5rem}.subvalue{font-size:85%;font-weight:400;opacity:.5}.card-title{font-weight:500}.card-sub-title{font-size:85%}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"] }, { kind: "ngmodule", type: ClipboardModule }, { kind: "directive", type: i2$1.CdkCopyToClipboard, selector: "[cdkCopyToClipboard]", inputs: ["cdkCopyToClipboard", "cdkCopyToClipboardAttempts"], outputs: ["cdkCopyToClipboardCopied"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }] });
618
+ }
619
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: ViewValueComponent, decorators: [{
620
+ type: Component,
621
+ args: [{ selector: 'view-value', imports: [NgClass, NgComponentOutlet, ClipboardModule, MatIcon], template: "<!-- EMPTY VALUE -->\n@if (value === undefined) { }\n\n<!-- SHOW VALUE -->\n@else {\n<div [style.color]=\"color\" [class.card-title]=\"isCardTitle\" [class.card-sub-title]=\"isCardSubTitle\">\n <div\n class=\"value\"\n [style.cursor]=\"hasClick || copyText ? 'pointer' : 'default'\"\n (click)=\"hasClick ? onClick() : copyText ? onCopy() : null\"\n [cdkCopyToClipboard]=\"copyText || ''\"\n >\n <ng-container *ngComponentOutlet=\"columnInfo[column.type].component; injector: injector\"></ng-container>\n <!-- CLICK -->\n @if (hasClick) { <mat-icon>open_in_new</mat-icon> }\n <!-- COPY -->\n @if (copyText) { <mat-icon>{{ isCopied ? 'done_all' : 'copy' }}</mat-icon> }\n </div>\n\n <!-- SUB VALUE -->\n @if (subValue) {\n <div class=\"subvalue\" [ngClass]=\"[subValue.isEN ? viewConfig.enClass : '']\">{{ subValue.value }}</div>\n }\n</div>\n}\n", styles: [".value{display:inline-flex;align-items:center}.value mat-icon{font-size:100%;padding:0 .5rem}.subvalue{font-size:85%;font-weight:400;opacity:.5}.card-title{font-weight:500}.card-sub-title{font-size:85%}\n"] }]
622
+ }], ctorParameters: () => [{ type: i1$1.Router }], propDecorators: { textAlign: [{
623
+ type: HostBinding,
624
+ args: ['style.text-align']
625
+ }], column: [{
626
+ type: Input,
627
+ args: [{ required: true }]
628
+ }], item: [{
629
+ type: Input,
630
+ args: [{ required: true }]
631
+ }], viewConfig: [{
632
+ type: Input,
633
+ args: [{ required: true }]
634
+ }], isDeactive: [{
635
+ type: Input,
636
+ args: [{ required: false }]
637
+ }], isCard: [{
638
+ type: Input,
639
+ args: [{ required: false }]
640
+ }], isCardTitle: [{
641
+ type: Input,
642
+ args: [{ required: false }]
643
+ }], isCardSubTitle: [{
644
+ type: Input,
645
+ args: [{ required: false }]
646
+ }] } });
647
+
648
+ class ViewService {
649
+ activatedRoute;
650
+ constructor(activatedRoute) {
651
+ this.activatedRoute = activatedRoute;
652
+ }
653
+ getTitleIndex(ngxTable) {
654
+ const index = ngxTable.columns.findIndex((l) => l.mode === 'TITLE');
655
+ return index === -1 ? 0 : index;
656
+ }
657
+ getSubTitleIndex(ngxTable) {
658
+ const index = ngxTable.columns.findIndex((l) => l.mode === 'SUBTITLE');
659
+ return index === -1 ? undefined : index;
660
+ }
661
+ getIcons(ngxTable, data) {
662
+ const iconFn = ngxTable.rows?.icon;
663
+ if (!iconFn)
664
+ return [];
665
+ return data.map((item) => {
666
+ const icon = iconFn(item);
667
+ return typeof icon === 'string' ? { icon } : icon;
668
+ });
669
+ }
670
+ getColors(ngxTable, data) {
671
+ const colorFn = ngxTable.rows?.color;
672
+ if (!colorFn)
673
+ return [];
674
+ return data.map((item) => colorFn(item));
675
+ }
676
+ getDescriptions(ngxTable, data) {
677
+ const descriptionFn = ngxTable.rows?.description;
678
+ if (!descriptionFn)
679
+ return [];
680
+ return data.map((item) => descriptionFn(item));
681
+ }
682
+ getDeactives(ngxTable, data) {
683
+ const deactives = [];
684
+ data.forEach((item, index) => {
685
+ if (ngxTable.rows?.isDeactive?.(item))
686
+ deactives.push(index);
687
+ });
688
+ return deactives;
689
+ }
690
+ getOrders(ngxTable) {
691
+ let defaultFound = false;
692
+ const orders = {};
693
+ // CHECK COLUMNS
694
+ ngxTable.columns.forEach((column) => {
695
+ if (!column.tools || !('order' in column.tools) || !column.tools.order)
696
+ return;
697
+ const title = column.title || '';
698
+ const key = column.tools.id;
699
+ const type = column.tools.order.type || 'ORDER';
700
+ const initial = type !== 'ORDER' ? type : column.tools.order.initial || 'ASC';
701
+ const isDefault = !defaultFound && !!column.tools.order.isDefault;
702
+ orders[key] = { title, type, initial, current: isDefault ? initial : undefined };
703
+ if (isDefault)
704
+ defaultFound = true;
705
+ });
706
+ if (Object.keys(orders).length === 0)
707
+ return {};
708
+ // CHECK QUERY PARAMS
709
+ const queryParams = { ...this.activatedRoute.snapshot.queryParams };
710
+ if (!!ngxTable.route && queryParams['ngx-table-order']) {
711
+ const param = queryParams['ngx-table-order'];
712
+ const index = param.lastIndexOf(':');
713
+ if (index !== -1) {
714
+ const id = param.substring(0, index);
715
+ const type = param.substring(index + 1);
716
+ if (orders[id] &&
717
+ (type === 'ASC' || type === 'DESC') &&
718
+ (orders[id].type === 'ORDER' || orders[id].type === type)) {
719
+ Object.keys(orders).forEach((key) => {
720
+ orders[key] = { ...orders[key], current: key === id ? type : undefined };
721
+ });
722
+ }
723
+ }
724
+ }
725
+ return orders;
726
+ }
727
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: ViewService, deps: [{ token: i1$1.ActivatedRoute }], target: i0.ɵɵFactoryTarget.Injectable });
728
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: ViewService });
729
+ }
730
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: ViewService, decorators: [{
731
+ type: Injectable
732
+ }], ctorParameters: () => [{ type: i1$1.ActivatedRoute }] });
733
+
734
+ class ViewCardToolbarComponent {
735
+ orders;
736
+ filters;
737
+ viewConfig;
738
+ orderChanged = new EventEmitter();
739
+ updateFilter = new EventEmitter();
740
+ clearFilter = new EventEmitter();
741
+ orderKeys = [];
742
+ filterKeys = [];
743
+ showClear = false;
744
+ swipeStart;
745
+ swipeLeft = 0;
746
+ ngOnChanges(changes) {
747
+ this.orderKeys = Object.keys(this.orders);
748
+ const activeKeys = [];
749
+ const deactiveKeys = [];
750
+ Object.keys(this.filters).forEach((key) => {
751
+ if (this.filters[key].value !== undefined)
752
+ activeKeys.push(key);
753
+ else
754
+ deactiveKeys.push(key);
755
+ });
756
+ this.filterKeys = [...activeKeys, ...deactiveKeys];
757
+ this.showClear = activeKeys.length > 2;
758
+ }
759
+ updateOrder(id, type) {
760
+ this.orderChanged.next({ id, type });
761
+ }
762
+ swipe(event, action, toolbar, container) {
763
+ if (toolbar.offsetWidth > container.offsetWidth)
764
+ return;
765
+ const clientX = event instanceof MouseEvent ? event.clientX : event.changedTouches[0].clientX;
766
+ switch (action) {
767
+ case 'START':
768
+ this.swipeStart = clientX - this.swipeLeft;
769
+ break;
770
+ case 'END':
771
+ this.swipeStart = undefined;
772
+ break;
773
+ case 'MOVE':
774
+ if (!this.swipeStart)
775
+ return;
776
+ let left = clientX - this.swipeStart;
777
+ if (left <= 0)
778
+ left = 0;
779
+ else if (left > container.offsetWidth - toolbar.offsetWidth)
780
+ left = container.offsetWidth - toolbar.offsetWidth;
781
+ this.swipeLeft = left;
782
+ container.style.left = `${left}px`;
783
+ break;
784
+ }
785
+ }
786
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: ViewCardToolbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
787
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.3", type: ViewCardToolbarComponent, isStandalone: true, selector: "view-card-toolbar", inputs: { orders: "orders", filters: "filters", viewConfig: "viewConfig" }, outputs: { orderChanged: "orderChanged", updateFilter: "updateFilter", clearFilter: "clearFilter" }, usesOnChanges: true, ngImport: i0, template: "<div\n class=\"toolbar\"\n [style.background-color]=\"viewConfig.paginationBackgroundColor\"\n [style.position]=\"viewConfig.stickyView?.headerTop ? 'sticky' : 'static'\"\n [style.top]=\"viewConfig.stickyView?.headerTop?.mobileView || undefined\"\n (mousedown)=\"swipe($event, 'START', toolbar, toolbarContainer)\"\n (mousemove)=\"swipe($event, 'MOVE', toolbar, toolbarContainer)\"\n (mouseup)=\"swipe($event, 'END', toolbar, toolbarContainer)\"\n (touchstart)=\"swipe($event, 'START', toolbar, toolbarContainer)\"\n (touchmove)=\"swipe($event, 'MOVE', toolbar, toolbarContainer)\"\n (touchend)=\"swipe($event, 'END', toolbar, toolbarContainer)\"\n #toolbar\n>\n <div class=\"toolbar-items\" #toolbarContainer>\n <!-- ORDER -->\n @if (orderKeys.length > 0) {\n <div class=\"item\" [style.border-color]=\"viewConfig.borderColor\" [matMenuTriggerFor]=\"orderMenu\">\n <mat-icon>swap_vert</mat-icon>\n <span>\u062A\u0631\u062A\u06CC\u0628 \u0646\u0645\u0627\u06CC\u0634</span>\n </div>\n <mat-menu #orderMenu=\"matMenu\" [xPosition]=\"'before'\" class=\"ngx-helper-order-menu\">\n @for (item of orderKeys; track $index) {\n <!-- DIVIDER -->\n @if ($index !== 0) {<mat-divider></mat-divider>}\n\n <!-- TYPES -->\n @switch (orders[item].type) {\n <!-- ORDR -->\n @case ('ORDER') {\n <button\n mat-menu-item\n type=\"button\"\n [disabled]=\"orders[item].current === 'ASC'\"\n (click)=\"updateOrder(item, 'ASC')\"\n >\n <mat-icon>north</mat-icon>\n <span>{{ orders[item].title }}</span>\n </button>\n <button\n mat-menu-item\n type=\"button\"\n [disabled]=\"orders[item].current === 'DESC'\"\n (click)=\"updateOrder(item, 'DESC')\"\n >\n <mat-icon>south</mat-icon>\n <span>{{ orders[item].title }}</span>\n </button>\n }\n <!-- ASC, DESC -->\n @default {\n <button\n mat-menu-item\n type=\"button\"\n [disabled]=\"orders[item].current\"\n (click)=\"updateOrder(item, orders[item].type)\"\n >\n <mat-icon>{{ orders[item].type === 'ASC' ? 'north' : 'south' }}</mat-icon>\n <span>{{ orders[item].title }}</span>\n </button>\n } } }\n </mat-menu>\n }\n\n <!-- CLEAR -->\n @if (showClear) {\n <div\n class=\"item\"\n [style.color]=\"viewConfig.highlightText\"\n [style.border-color]=\"viewConfig.highlightText\"\n [style.background-color]=\"viewConfig.highlightBackground\"\n (click)=\"clearFilter.next()\"\n >\n <span>\u0644\u063A\u0648 \u0641\u06CC\u0644\u062A\u0631\u0647\u0627</span>\n <mat-icon>filter_alt_off</mat-icon>\n </div>\n\n }\n\n <!-- FILTER -->\n @for (item of filterKeys; track $index) {\n <div\n class=\"item\"\n [style.color]=\"filters[item].value ? viewConfig.highlightText : ''\"\n [style.border-color]=\"filters[item].value ? viewConfig.highlightText : viewConfig.borderColor\"\n [style.background-color]=\"filters[item].value ? viewConfig.highlightBackground : ''\"\n (click)=\"updateFilter.next(item)\"\n >\n <mat-icon>filter_alt</mat-icon>\n <span>{{ filters[item].title }}</span>\n </div>\n }\n </div>\n</div>\n\n<div\n class=\"seperator\"\n [style.background-color]=\"viewConfig.backgroundColor\"\n [style.position]=\"viewConfig.stickyView?.headerTop ? 'sticky' : 'static'\"\n [style.top]=\"'calc(' + (viewConfig.stickyView?.headerTop?.mobileView || undefined) + ' + var(--toolbarHeight) + 2px)'\"\n></div>\n", styles: [".toolbar{z-index:2;height:calc(var(--toolbarHeight) + 2px);overflow-x:hidden}.toolbar .toolbar-items{display:inline-flex;align-items:center;column-gap:.5rem;position:relative;left:0}.toolbar .toolbar-items .item{display:flex;align-items:center;column-gap:.25rem;padding:0 .5rem;border-radius:8px;border:1px solid transparent;height:var(--toolbarHeight)}.toolbar .toolbar-items .item mat-icon{font-size:100%}.toolbar .toolbar-items .item span{font-size:80%;white-space:nowrap}.seperator{z-index:2;height:1rem}\n"], dependencies: [{ kind: "component", type: MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i1$2.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: i1$2.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i1$2.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }] });
788
+ }
789
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: ViewCardToolbarComponent, decorators: [{
790
+ type: Component,
791
+ args: [{ selector: 'view-card-toolbar', imports: [MatDivider, MatIcon, MatMenuModule], template: "<div\n class=\"toolbar\"\n [style.background-color]=\"viewConfig.paginationBackgroundColor\"\n [style.position]=\"viewConfig.stickyView?.headerTop ? 'sticky' : 'static'\"\n [style.top]=\"viewConfig.stickyView?.headerTop?.mobileView || undefined\"\n (mousedown)=\"swipe($event, 'START', toolbar, toolbarContainer)\"\n (mousemove)=\"swipe($event, 'MOVE', toolbar, toolbarContainer)\"\n (mouseup)=\"swipe($event, 'END', toolbar, toolbarContainer)\"\n (touchstart)=\"swipe($event, 'START', toolbar, toolbarContainer)\"\n (touchmove)=\"swipe($event, 'MOVE', toolbar, toolbarContainer)\"\n (touchend)=\"swipe($event, 'END', toolbar, toolbarContainer)\"\n #toolbar\n>\n <div class=\"toolbar-items\" #toolbarContainer>\n <!-- ORDER -->\n @if (orderKeys.length > 0) {\n <div class=\"item\" [style.border-color]=\"viewConfig.borderColor\" [matMenuTriggerFor]=\"orderMenu\">\n <mat-icon>swap_vert</mat-icon>\n <span>\u062A\u0631\u062A\u06CC\u0628 \u0646\u0645\u0627\u06CC\u0634</span>\n </div>\n <mat-menu #orderMenu=\"matMenu\" [xPosition]=\"'before'\" class=\"ngx-helper-order-menu\">\n @for (item of orderKeys; track $index) {\n <!-- DIVIDER -->\n @if ($index !== 0) {<mat-divider></mat-divider>}\n\n <!-- TYPES -->\n @switch (orders[item].type) {\n <!-- ORDR -->\n @case ('ORDER') {\n <button\n mat-menu-item\n type=\"button\"\n [disabled]=\"orders[item].current === 'ASC'\"\n (click)=\"updateOrder(item, 'ASC')\"\n >\n <mat-icon>north</mat-icon>\n <span>{{ orders[item].title }}</span>\n </button>\n <button\n mat-menu-item\n type=\"button\"\n [disabled]=\"orders[item].current === 'DESC'\"\n (click)=\"updateOrder(item, 'DESC')\"\n >\n <mat-icon>south</mat-icon>\n <span>{{ orders[item].title }}</span>\n </button>\n }\n <!-- ASC, DESC -->\n @default {\n <button\n mat-menu-item\n type=\"button\"\n [disabled]=\"orders[item].current\"\n (click)=\"updateOrder(item, orders[item].type)\"\n >\n <mat-icon>{{ orders[item].type === 'ASC' ? 'north' : 'south' }}</mat-icon>\n <span>{{ orders[item].title }}</span>\n </button>\n } } }\n </mat-menu>\n }\n\n <!-- CLEAR -->\n @if (showClear) {\n <div\n class=\"item\"\n [style.color]=\"viewConfig.highlightText\"\n [style.border-color]=\"viewConfig.highlightText\"\n [style.background-color]=\"viewConfig.highlightBackground\"\n (click)=\"clearFilter.next()\"\n >\n <span>\u0644\u063A\u0648 \u0641\u06CC\u0644\u062A\u0631\u0647\u0627</span>\n <mat-icon>filter_alt_off</mat-icon>\n </div>\n\n }\n\n <!-- FILTER -->\n @for (item of filterKeys; track $index) {\n <div\n class=\"item\"\n [style.color]=\"filters[item].value ? viewConfig.highlightText : ''\"\n [style.border-color]=\"filters[item].value ? viewConfig.highlightText : viewConfig.borderColor\"\n [style.background-color]=\"filters[item].value ? viewConfig.highlightBackground : ''\"\n (click)=\"updateFilter.next(item)\"\n >\n <mat-icon>filter_alt</mat-icon>\n <span>{{ filters[item].title }}</span>\n </div>\n }\n </div>\n</div>\n\n<div\n class=\"seperator\"\n [style.background-color]=\"viewConfig.backgroundColor\"\n [style.position]=\"viewConfig.stickyView?.headerTop ? 'sticky' : 'static'\"\n [style.top]=\"'calc(' + (viewConfig.stickyView?.headerTop?.mobileView || undefined) + ' + var(--toolbarHeight) + 2px)'\"\n></div>\n", styles: [".toolbar{z-index:2;height:calc(var(--toolbarHeight) + 2px);overflow-x:hidden}.toolbar .toolbar-items{display:inline-flex;align-items:center;column-gap:.5rem;position:relative;left:0}.toolbar .toolbar-items .item{display:flex;align-items:center;column-gap:.25rem;padding:0 .5rem;border-radius:8px;border:1px solid transparent;height:var(--toolbarHeight)}.toolbar .toolbar-items .item mat-icon{font-size:100%}.toolbar .toolbar-items .item span{font-size:80%;white-space:nowrap}.seperator{z-index:2;height:1rem}\n"] }]
792
+ }], propDecorators: { orders: [{
793
+ type: Input,
794
+ args: [{ required: true }]
795
+ }], filters: [{
796
+ type: Input,
797
+ args: [{ required: true }]
798
+ }], viewConfig: [{
799
+ type: Input,
800
+ args: [{ required: true }]
801
+ }], orderChanged: [{
802
+ type: Output
803
+ }], updateFilter: [{
804
+ type: Output
805
+ }], clearFilter: [{
806
+ type: Output
807
+ }] } });
808
+
809
+ class ViewCardComponent {
810
+ filterService;
811
+ viewService;
812
+ toolbarHeight = '32px';
813
+ ngxTable;
814
+ data;
815
+ viewConfig;
816
+ orderChanged = new EventEmitter();
817
+ filterChanged = new EventEmitter();
818
+ filterCleared = new EventEmitter();
819
+ hasIcon = false;
820
+ hasAction = false;
821
+ titleIndex;
822
+ subTitleIndex;
823
+ icons = [];
824
+ colors = [];
825
+ descriptions = [];
826
+ deactives = [];
827
+ orders;
828
+ filters;
829
+ hasToolbar = false;
830
+ headerTop = '';
831
+ hasContent;
832
+ constructor(filterService, viewService) {
833
+ this.filterService = filterService;
834
+ this.viewService = viewService;
835
+ }
836
+ ngOnChanges(changes) {
837
+ this.hasIcon = !!this.ngxTable.rows?.icon;
838
+ this.hasAction = (this.ngxTable.actions || []).length > 0;
839
+ this.titleIndex = this.viewService.getTitleIndex(this.ngxTable);
840
+ this.subTitleIndex = this.viewService.getSubTitleIndex(this.ngxTable);
841
+ this.icons = this.viewService.getIcons(this.ngxTable, this.data);
842
+ this.colors = this.viewService.getColors(this.ngxTable, this.data);
843
+ this.descriptions = this.viewService.getDescriptions(this.ngxTable, this.data);
844
+ this.deactives = this.viewService.getDeactives(this.ngxTable, this.data);
845
+ this.orders = this.viewService.getOrders(this.ngxTable);
846
+ this.filters = this.filterService.getFilters(this.ngxTable);
847
+ this.hasToolbar = Object.keys(this.orders).length > 0 || Object.keys(this.filters).length > 0;
848
+ const top = this.viewConfig.stickyView?.headerTop?.mobileView;
849
+ this.headerTop = top ? (this.hasToolbar ? `calc(${top} + var(--toolbarHeight) + 1rem + 2px)` : top) : '';
850
+ this.hasContent = this.ngxTable.columns.some((_, index) => index != this.titleIndex && index !== this.subTitleIndex);
851
+ }
852
+ updateFilter(id) {
853
+ const filter = this.filters[id];
854
+ if (!filter)
855
+ return;
856
+ this.filterService.updateFilter(filter, this.viewConfig).then((filter) => {
857
+ if (!filter)
858
+ return;
859
+ this.filters[id] = filter;
860
+ this.filterChanged.next({ id, value: filter.value });
861
+ });
862
+ }
863
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: ViewCardComponent, deps: [{ token: FilterService }, { token: ViewService }], target: i0.ɵɵFactoryTarget.Component });
864
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.3", type: ViewCardComponent, isStandalone: true, selector: "view-card", inputs: { ngxTable: "ngxTable", data: "data", viewConfig: "viewConfig" }, outputs: { orderChanged: "orderChanged", filterChanged: "filterChanged", filterCleared: "filterCleared" }, host: { properties: { "style.--toolbarHeight": "this.toolbarHeight" } }, providers: [FilterService, ViewService], usesOnChanges: true, ngImport: i0, template: "<!-- TOOLBAR -->\n@if (hasToolbar) {\n<view-card-toolbar\n [orders]=\"orders\"\n [filters]=\"filters\"\n [viewConfig]=\"viewConfig\"\n (orderChanged)=\"orderChanged.next($event)\"\n (updateFilter)=\"updateFilter($event)\"\n (clearFilter)=\"filterCleared.next()\"\n></view-card-toolbar>\n}\n\n<!-- DATA -->\n<div class=\"data\">\n @for (item of data; track $index; let dataIndex = $index) {\n <section [style.border-color]=\"viewConfig.borderColor\">\n <header\n [style.border-color]=\"viewConfig.borderColor\"\n [style.background-color]=\"viewConfig.headerBackgroundColor\"\n [style.position]=\"viewConfig.stickyView?.headerTop ? 'sticky' : 'static'\"\n [style.top]=\"headerTop\"\n >\n <!-- ICON -->\n @if (hasIcon) {\n <mat-icon [style.color]=\"icons[$index].color\" [style.font-size]=\"viewConfig.iconSize\">\n {{ icons[$index].icon }}\n </mat-icon>\n }\n\n <!-- TITLE -->\n <div class=\"title\" [style.color]=\"viewConfig.headerTextColor\">\n <view-value\n [column]=\"ngxTable.columns[this.titleIndex]\"\n [item]=\"item\"\n [viewConfig]=\"viewConfig\"\n [isDeactive]=\"deactives.includes(dataIndex)\"\n [isCard]=\"true\"\n [isCardTitle]=\"true\"\n ></view-value>\n <!-- SUB TITLE -->\n @if (subTitleIndex) {\n <view-value\n [column]=\"ngxTable.columns[this.subTitleIndex]\"\n [item]=\"item\"\n [viewConfig]=\"viewConfig\"\n [isCard]=\"true\"\n [isCardSubTitle]=\"true\"\n ></view-value>\n }\n </div>\n\n <!-- ACTION -->\n @if (hasAction) {\n <view-action\n [actions]=\"ngxTable.actions || []\"\n [item]=\"item\"\n [viewConfig]=\"viewConfig\"\n [isMobile]=\"true\"\n ></view-action>\n }\n </header>\n\n <!-- CONTENT -->\n @if (hasContent) {\n <content\n [style.border-color]=\"viewConfig.borderColor\"\n [style.color]=\"colors[dataIndex]\"\n [style.backgroundColor]=\"viewConfig.cardBackgroundColor\"\n >\n @for (column of ngxTable.columns; track $index; let columnIndex = $index) {\n <!-- CHECK TITLE AND SUBTITLE -->\n @if (columnIndex !== titleIndex && columnIndex !== subTitleIndex) {\n <div class=\"item\">\n <div class=\"title\">{{ column.title }}:</div>\n <div class=\"value\">\n <view-value [column]=\"column\" [item]=\"item\" [viewConfig]=\"viewConfig\" [isCard]=\"true\"></view-value>\n </div>\n </div>\n } }\n\n <!-- DESCRIPTION -->\n @if (descriptions[dataIndex]) {\n <div\n class=\"description\"\n [style.border-color]=\"viewConfig.borderColor\"\n [innerHTML]=\"descriptions[dataIndex] || '' | ngxHelperMultiLine\"\n ></div>\n }\n </content>\n }\n </section>\n }\n</div>\n", styles: [".data{display:flex;flex-direction:column;row-gap:1rem}.data section{border-bottom:1px solid transparent}.data section header{display:flex;align-items:flex-start;column-gap:.75rem;z-index:1;padding-right:.75rem;border:1px solid transparent;border-bottom-width:0}.data section header mat-icon{padding:.75rem 0}.data section header .title{flex:1;padding:.75rem 0}.data section content{display:block;padding:1rem 0 .5rem;border:1px solid transparent;border-top-width:0;border-bottom-width:0}.data section content .item{display:flex;align-items:flex-start;column-gap:1rem;padding:0 1rem .5rem}.data section content .item .title{width:25%;font-size:85%;font-weight:500}.data section content .item .value{flex:1}.data section content .description{text-align:justify;font-size:85%;line-height:1.5;margin-top:.5rem;padding:.75rem 1rem 0;border-top:1px solid transparent}::ng-deep .ngx-helper-order-menu mat-icon{font-size:100%;margin:0 0 0 .75rem!important}::ng-deep .ngx-helper-order-menu .mat-mdc-menu-content{padding:0}::ng-deep .ngx-helper-order-menu .mat-mdc-menu-item{direction:rtl;text-align:right}::ng-deep .ngx-helper-order-menu .mat-mdc-menu-item .mat-mdc-menu-item-text{font-size:90%!important}::ng-deep .ngx-helper-order-menu .mat-divider{margin:0!important;border-top-color:var(--outline-variant)}\n"], dependencies: [{ kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "pipe", type: NgxHelperMultiLinePipe, name: "ngxHelperMultiLine" }, { kind: "component", type: ViewActionComponent, selector: "view-action", inputs: ["actions", "item", "viewConfig", "isMobile"] }, { kind: "component", type: ViewValueComponent, selector: "view-value", inputs: ["column", "item", "viewConfig", "isDeactive", "isCard", "isCardTitle", "isCardSubTitle"] }, { kind: "component", type: ViewCardToolbarComponent, selector: "view-card-toolbar", inputs: ["orders", "filters", "viewConfig"], outputs: ["orderChanged", "updateFilter", "clearFilter"] }] });
865
+ }
866
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: ViewCardComponent, decorators: [{
867
+ type: Component,
868
+ args: [{ selector: 'view-card', imports: [MatIcon, NgxHelperMultiLinePipe, ViewActionComponent, ViewValueComponent, ViewCardToolbarComponent], providers: [FilterService, ViewService], template: "<!-- TOOLBAR -->\n@if (hasToolbar) {\n<view-card-toolbar\n [orders]=\"orders\"\n [filters]=\"filters\"\n [viewConfig]=\"viewConfig\"\n (orderChanged)=\"orderChanged.next($event)\"\n (updateFilter)=\"updateFilter($event)\"\n (clearFilter)=\"filterCleared.next()\"\n></view-card-toolbar>\n}\n\n<!-- DATA -->\n<div class=\"data\">\n @for (item of data; track $index; let dataIndex = $index) {\n <section [style.border-color]=\"viewConfig.borderColor\">\n <header\n [style.border-color]=\"viewConfig.borderColor\"\n [style.background-color]=\"viewConfig.headerBackgroundColor\"\n [style.position]=\"viewConfig.stickyView?.headerTop ? 'sticky' : 'static'\"\n [style.top]=\"headerTop\"\n >\n <!-- ICON -->\n @if (hasIcon) {\n <mat-icon [style.color]=\"icons[$index].color\" [style.font-size]=\"viewConfig.iconSize\">\n {{ icons[$index].icon }}\n </mat-icon>\n }\n\n <!-- TITLE -->\n <div class=\"title\" [style.color]=\"viewConfig.headerTextColor\">\n <view-value\n [column]=\"ngxTable.columns[this.titleIndex]\"\n [item]=\"item\"\n [viewConfig]=\"viewConfig\"\n [isDeactive]=\"deactives.includes(dataIndex)\"\n [isCard]=\"true\"\n [isCardTitle]=\"true\"\n ></view-value>\n <!-- SUB TITLE -->\n @if (subTitleIndex) {\n <view-value\n [column]=\"ngxTable.columns[this.subTitleIndex]\"\n [item]=\"item\"\n [viewConfig]=\"viewConfig\"\n [isCard]=\"true\"\n [isCardSubTitle]=\"true\"\n ></view-value>\n }\n </div>\n\n <!-- ACTION -->\n @if (hasAction) {\n <view-action\n [actions]=\"ngxTable.actions || []\"\n [item]=\"item\"\n [viewConfig]=\"viewConfig\"\n [isMobile]=\"true\"\n ></view-action>\n }\n </header>\n\n <!-- CONTENT -->\n @if (hasContent) {\n <content\n [style.border-color]=\"viewConfig.borderColor\"\n [style.color]=\"colors[dataIndex]\"\n [style.backgroundColor]=\"viewConfig.cardBackgroundColor\"\n >\n @for (column of ngxTable.columns; track $index; let columnIndex = $index) {\n <!-- CHECK TITLE AND SUBTITLE -->\n @if (columnIndex !== titleIndex && columnIndex !== subTitleIndex) {\n <div class=\"item\">\n <div class=\"title\">{{ column.title }}:</div>\n <div class=\"value\">\n <view-value [column]=\"column\" [item]=\"item\" [viewConfig]=\"viewConfig\" [isCard]=\"true\"></view-value>\n </div>\n </div>\n } }\n\n <!-- DESCRIPTION -->\n @if (descriptions[dataIndex]) {\n <div\n class=\"description\"\n [style.border-color]=\"viewConfig.borderColor\"\n [innerHTML]=\"descriptions[dataIndex] || '' | ngxHelperMultiLine\"\n ></div>\n }\n </content>\n }\n </section>\n }\n</div>\n", styles: [".data{display:flex;flex-direction:column;row-gap:1rem}.data section{border-bottom:1px solid transparent}.data section header{display:flex;align-items:flex-start;column-gap:.75rem;z-index:1;padding-right:.75rem;border:1px solid transparent;border-bottom-width:0}.data section header mat-icon{padding:.75rem 0}.data section header .title{flex:1;padding:.75rem 0}.data section content{display:block;padding:1rem 0 .5rem;border:1px solid transparent;border-top-width:0;border-bottom-width:0}.data section content .item{display:flex;align-items:flex-start;column-gap:1rem;padding:0 1rem .5rem}.data section content .item .title{width:25%;font-size:85%;font-weight:500}.data section content .item .value{flex:1}.data section content .description{text-align:justify;font-size:85%;line-height:1.5;margin-top:.5rem;padding:.75rem 1rem 0;border-top:1px solid transparent}::ng-deep .ngx-helper-order-menu mat-icon{font-size:100%;margin:0 0 0 .75rem!important}::ng-deep .ngx-helper-order-menu .mat-mdc-menu-content{padding:0}::ng-deep .ngx-helper-order-menu .mat-mdc-menu-item{direction:rtl;text-align:right}::ng-deep .ngx-helper-order-menu .mat-mdc-menu-item .mat-mdc-menu-item-text{font-size:90%!important}::ng-deep .ngx-helper-order-menu .mat-divider{margin:0!important;border-top-color:var(--outline-variant)}\n"] }]
869
+ }], ctorParameters: () => [{ type: FilterService }, { type: ViewService }], propDecorators: { toolbarHeight: [{
870
+ type: HostBinding,
871
+ args: ['style.--toolbarHeight']
872
+ }], ngxTable: [{
873
+ type: Input,
874
+ args: [{ required: true }]
875
+ }], data: [{
876
+ type: Input,
877
+ args: [{ required: true }]
878
+ }], viewConfig: [{
879
+ type: Input,
880
+ args: [{ required: true }]
881
+ }], orderChanged: [{
882
+ type: Output
883
+ }], filterChanged: [{
884
+ type: Output
885
+ }], filterCleared: [{
886
+ type: Output
887
+ }] } });
888
+
889
+ class ViewPaginationComponent {
890
+ elementRef;
891
+ stylePosition;
892
+ styleBottom;
893
+ type;
894
+ pagination;
895
+ viewConfig;
896
+ isMobile;
897
+ stickyBottom;
898
+ pageChanged = new EventEmitter();
899
+ pages = [];
900
+ hasShadow = false;
901
+ constructor(elementRef) {
902
+ this.elementRef = elementRef;
903
+ }
904
+ ngOnInit() {
905
+ setTimeout(this.onScroll.bind(this), 0);
906
+ }
907
+ ngOnChanges(changes) {
908
+ const isDefaultPage = (page) => page === 1 || page === this.pagination.page.total;
909
+ const period = Math.floor(this.pagination.page.total / 8) || 1;
910
+ const trunc = period < 100 ? 10 : period < 1000 ? 100 : 1000;
911
+ this.pages = Array(this.pagination.page.total)
912
+ .fill('0')
913
+ .map((_, index) => index + 1)
914
+ .filter((page) => page !== this.pagination.page.current)
915
+ .filter((page) => isDefaultPage(page) || (page - 1) % period === 0)
916
+ .map((page) => (isDefaultPage(page) || period < 10 ? page : page - (page % trunc)));
917
+ this.stylePosition = this.stickyBottom ? 'sticky' : 'static';
918
+ this.styleBottom = this.stickyBottom
919
+ ? this.isMobile
920
+ ? this.stickyBottom.mobileView
921
+ : this.stickyBottom.desktopView
922
+ : '';
923
+ }
924
+ onScroll() {
925
+ if (!this.elementRef)
926
+ return;
927
+ const element = this.elementRef.nativeElement;
928
+ const elementPosition = element.offsetTop + element.offsetHeight + 8;
929
+ const parentHeight = element.parentElement?.offsetHeight;
930
+ this.hasShadow = !!parentHeight && elementPosition < parentHeight;
931
+ }
932
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: ViewPaginationComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
933
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.3", type: ViewPaginationComponent, isStandalone: true, selector: "view-pagination", inputs: { type: "type", pagination: "pagination", viewConfig: "viewConfig", isMobile: "isMobile", stickyBottom: "stickyBottom" }, outputs: { pageChanged: "pageChanged" }, host: { listeners: { "window:scroll": "onScroll($event)" }, properties: { "style.position": "this.stylePosition", "style.bottom": "this.styleBottom" } }, usesOnChanges: true, ngImport: i0, template: "<content\n [class.desktop]=\"!isMobile\"\n [class.mobile]=\"isMobile\"\n [class.shadow]=\"hasShadow\"\n [style.backgroundColor]=\"viewConfig.paginationBackgroundColor\"\n>\n <section>\n <div class=\"title\">\u0635\u0641\u062D\u0647 {{ pagination.page.current | number }} \u0627\u0632 {{ pagination.page.total | number }}</div>\n <div class=\"total\">{{ pagination.item.total | number }} {{ type }}</div>\n </section>\n\n <button\n mat-icon-button\n type=\"button\"\n [disabled]=\"pagination.page.current === pagination.page.total\"\n (click)=\"pageChanged.next(pagination.page.total)\"\n >\n <mat-icon>keyboard_double_arrow_right</mat-icon>\n </button>\n <button\n mat-icon-button\n type=\"button\"\n [disabled]=\"pagination.page.current === pagination.page.total\"\n (click)=\"pageChanged.next(pagination.page.current + 1)\"\n >\n <mat-icon>chevron_right</mat-icon>\n </button>\n\n <button mat-icon-button [matMenuTriggerFor]=\"pageMenu\"><mat-icon>tag</mat-icon></button>\n <mat-menu #pageMenu=\"matMenu\">\n @for (page of pages; track $index) {\n <button\n mat-menu-item\n type=\"button\"\n [disabled]=\"page === pagination.page.current\"\n class=\"pagination-menu-item\"\n (click)=\"pageChanged.next(page)\"\n >\n {{ page | number }}\n </button>\n }\n </mat-menu>\n\n <button\n mat-icon-button\n type=\"button\"\n [disabled]=\"pagination.page.current === 1\"\n (click)=\"pageChanged.next(pagination.page.current - 1)\"\n >\n <mat-icon>chevron_left</mat-icon>\n </button>\n <button mat-icon-button type=\"button\" [disabled]=\"pagination.page.current === 1\" (click)=\"pageChanged.next(1)\">\n <mat-icon>keyboard_double_arrow_left</mat-icon>\n </button>\n</content>\n", styles: [":host{display:block;margin-top:1rem;z-index:1}:host content{display:flex;align-items:center;margin:0 auto;padding:.5rem 0;background-color:var(--surface-container-low);border-radius:8px;border:1px solid var(--surface-container-highest)}:host content section{display:block;padding-right:.75rem}:host content section .title{font-weight:500;line-height:1}:host content section .total{font-size:80%;opacity:.75;line-height:1;margin-top:.25rem}:host content.desktop{column-gap:.5rem;width:fit-content}:host content.desktop section{min-width:250px}:host content.mobile section{flex:1}:host content.shadow{border:1px solid var(--outline-variant);box-shadow:0 0 10px 0 var(--outline-variant)}::ng-deep .pagination-menu-item{text-align:center!important}\n"], dependencies: [{ kind: "pipe", type: DecimalPipe, name: "number" }, { kind: "component", type: MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i1$2.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: i1$2.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i1$2.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }] });
934
+ }
935
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: ViewPaginationComponent, decorators: [{
936
+ type: Component,
937
+ args: [{ selector: 'view-pagination', host: { '(window:scroll)': 'onScroll($event)' }, imports: [DecimalPipe, MatIconButton, MatIcon, MatMenuModule], template: "<content\n [class.desktop]=\"!isMobile\"\n [class.mobile]=\"isMobile\"\n [class.shadow]=\"hasShadow\"\n [style.backgroundColor]=\"viewConfig.paginationBackgroundColor\"\n>\n <section>\n <div class=\"title\">\u0635\u0641\u062D\u0647 {{ pagination.page.current | number }} \u0627\u0632 {{ pagination.page.total | number }}</div>\n <div class=\"total\">{{ pagination.item.total | number }} {{ type }}</div>\n </section>\n\n <button\n mat-icon-button\n type=\"button\"\n [disabled]=\"pagination.page.current === pagination.page.total\"\n (click)=\"pageChanged.next(pagination.page.total)\"\n >\n <mat-icon>keyboard_double_arrow_right</mat-icon>\n </button>\n <button\n mat-icon-button\n type=\"button\"\n [disabled]=\"pagination.page.current === pagination.page.total\"\n (click)=\"pageChanged.next(pagination.page.current + 1)\"\n >\n <mat-icon>chevron_right</mat-icon>\n </button>\n\n <button mat-icon-button [matMenuTriggerFor]=\"pageMenu\"><mat-icon>tag</mat-icon></button>\n <mat-menu #pageMenu=\"matMenu\">\n @for (page of pages; track $index) {\n <button\n mat-menu-item\n type=\"button\"\n [disabled]=\"page === pagination.page.current\"\n class=\"pagination-menu-item\"\n (click)=\"pageChanged.next(page)\"\n >\n {{ page | number }}\n </button>\n }\n </mat-menu>\n\n <button\n mat-icon-button\n type=\"button\"\n [disabled]=\"pagination.page.current === 1\"\n (click)=\"pageChanged.next(pagination.page.current - 1)\"\n >\n <mat-icon>chevron_left</mat-icon>\n </button>\n <button mat-icon-button type=\"button\" [disabled]=\"pagination.page.current === 1\" (click)=\"pageChanged.next(1)\">\n <mat-icon>keyboard_double_arrow_left</mat-icon>\n </button>\n</content>\n", styles: [":host{display:block;margin-top:1rem;z-index:1}:host content{display:flex;align-items:center;margin:0 auto;padding:.5rem 0;background-color:var(--surface-container-low);border-radius:8px;border:1px solid var(--surface-container-highest)}:host content section{display:block;padding-right:.75rem}:host content section .title{font-weight:500;line-height:1}:host content section .total{font-size:80%;opacity:.75;line-height:1;margin-top:.25rem}:host content.desktop{column-gap:.5rem;width:fit-content}:host content.desktop section{min-width:250px}:host content.mobile section{flex:1}:host content.shadow{border:1px solid var(--outline-variant);box-shadow:0 0 10px 0 var(--outline-variant)}::ng-deep .pagination-menu-item{text-align:center!important}\n"] }]
938
+ }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { stylePosition: [{
939
+ type: HostBinding,
940
+ args: ['style.position']
941
+ }], styleBottom: [{
942
+ type: HostBinding,
943
+ args: ['style.bottom']
944
+ }], type: [{
945
+ type: Input,
946
+ args: [{ required: true }]
947
+ }], pagination: [{
948
+ type: Input,
949
+ args: [{ required: true }]
950
+ }], viewConfig: [{
951
+ type: Input,
952
+ args: [{ required: true }]
953
+ }], isMobile: [{
954
+ type: Input,
955
+ args: [{ required: true }]
956
+ }], stickyBottom: [{
957
+ type: Input,
958
+ args: [{ required: true }]
959
+ }], pageChanged: [{
960
+ type: Output
961
+ }] } });
962
+
963
+ class ViewTableComponent {
964
+ viewService;
965
+ filterService;
966
+ ngxTable;
967
+ data;
968
+ viewConfig;
969
+ orderChanged = new EventEmitter();
970
+ filterChanged = new EventEmitter();
971
+ filterCleared = new EventEmitter();
972
+ hasIcon = false;
973
+ hasAction = false;
974
+ titleIndex;
975
+ subTitleIndex;
976
+ icons = [];
977
+ colors = [];
978
+ descriptions = [];
979
+ deactives = [];
980
+ orders;
981
+ filters;
982
+ activeFilters = [];
983
+ constructor(viewService, filterService) {
984
+ this.viewService = viewService;
985
+ this.filterService = filterService;
986
+ }
987
+ ngOnChanges(changes) {
988
+ this.hasIcon = !!this.ngxTable.rows?.icon;
989
+ this.hasAction = (this.ngxTable.actions || []).length > 0;
990
+ this.titleIndex = this.viewService.getTitleIndex(this.ngxTable);
991
+ this.subTitleIndex = this.viewService.getSubTitleIndex(this.ngxTable);
992
+ this.icons = this.viewService.getIcons(this.ngxTable, this.data);
993
+ this.colors = this.viewService.getColors(this.ngxTable, this.data);
994
+ this.descriptions = this.viewService.getDescriptions(this.ngxTable, this.data);
995
+ this.deactives = this.viewService.getDeactives(this.ngxTable, this.data);
996
+ this.orders = this.viewService.getOrders(this.ngxTable);
997
+ this.filters = this.filterService.getFilters(this.ngxTable);
998
+ this.activeFilters = Object.keys(this.filters)
999
+ .filter((id) => this.filters[id].value !== undefined)
1000
+ .map((id) => ({
1001
+ id,
1002
+ title: this.filters[id].title,
1003
+ ...FilterInfo[this.filters[id].filter.type].methods.active(this.filters[id].value, this.filters[id].filter),
1004
+ }));
1005
+ }
1006
+ updateOrder(id) {
1007
+ const order = this.orders[id];
1008
+ if (!order || order.type === order.current)
1009
+ return;
1010
+ const type = order.current ? (order.current === 'ASC' ? 'DESC' : 'ASC') : order.initial;
1011
+ this.orderChanged.next({ id, type });
1012
+ }
1013
+ updateFilter(id) {
1014
+ const filter = this.filters[id];
1015
+ if (!filter)
1016
+ return;
1017
+ this.filterService.updateFilter(filter, this.viewConfig).then((filter) => {
1018
+ if (!filter)
1019
+ return;
1020
+ this.filters[id] = filter;
1021
+ this.filterChanged.next({ id, value: filter.value });
1022
+ });
1023
+ }
1024
+ clearFilter(id) {
1025
+ const filter = this.filters[id];
1026
+ if (!filter)
1027
+ return;
1028
+ this.filters[id] = { ...this.filters[id], value: undefined };
1029
+ this.filterChanged.next({ id, value: undefined });
1030
+ }
1031
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: ViewTableComponent, deps: [{ token: ViewService }, { token: FilterService }], target: i0.ɵɵFactoryTarget.Component });
1032
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.3", type: ViewTableComponent, isStandalone: true, selector: "view-table", inputs: { ngxTable: "ngxTable", data: "data", viewConfig: "viewConfig" }, outputs: { orderChanged: "orderChanged", filterChanged: "filterChanged", filterCleared: "filterCleared" }, providers: [FilterService, ViewService], usesOnChanges: true, ngImport: i0, template: "<table [cellPadding]=\"0\" [cellSpacing]=\"0\" [width]=\"'100%'\" [border]=\"0\">\n <!-- HEADER -->\n\n <thead\n [style.color]=\"viewConfig.headerTextColor\"\n [style.background-color]=\"viewConfig.headerBackgroundColor\"\n [style.position]=\"viewConfig.stickyView?.headerTop ? 'sticky' : 'static'\"\n [style.top]=\"viewConfig.stickyView?.headerTop?.desktopView || undefined\"\n >\n <!-- ACTIVE FILTERS -->\n @if (activeFilters.length > 0) {\n <tr>\n <!-- ICON -->\n @if (hasIcon) {\n <th class=\"active-filters\" [style.border-color]=\"viewConfig.borderColor\"></th>\n }\n\n <!-- TOOLBAR -->\n <th\n class=\"active-filters\"\n [colSpan]=\"ngxTable.columns.length + (this.hasAction ? 1 : 0)\"\n [style.border-color]=\"viewConfig.borderColor\"\n >\n <div class=\"toolbar\" [@toolbar]>\n @for (item of activeFilters; track $index) {\n <div class=\"item\" [style.border-color]=\"viewConfig.borderColor\">\n <div class=\"title\" (click)=\"updateFilter(item.id)\">{{ item.title }}:</div>\n <div\n class=\"value\"\n (click)=\"updateFilter(item.id)\"\n [ngClass]=\"item.english ? viewConfig.enClass : ''\"\n >\n {{ item.value }}\n </div>\n <div class=\"icon\" (click)=\"clearFilter(item.id)\">\n <mat-icon>close</mat-icon>\n </div>\n </div>\n }\n\n <!-- CLEAR ALL -->\n @if (activeFilters.length > 2) {\n <div\n class=\"clear\"\n [style.border-color]=\"viewConfig.highlightText\"\n [style.color]=\"viewConfig.highlightText\"\n [style.background-color]=\"viewConfig.highlightBackground\"\n (click)=\"filterCleared.next()\"\n >\n <div class=\"title\">\u0644\u063A\u0648 \u0641\u06CC\u0644\u062A\u0631\u0647\u0627</div>\n <mat-icon>filter_alt_off</mat-icon>\n </div>\n }\n </div>\n </th>\n </tr>\n }\n\n <tr>\n <!-- ICON -->\n @if (hasIcon) {\n <th></th>\n }\n\n <!-- COLUMNS -->\n @for (column of ngxTable.columns; track $index) {\n <th [style.text-align]=\"(column.textAlign || 'RIGHT').toLowerCase()\">\n <div class=\"column\">\n <div class=\"title\">{{ column.title }}</div>\n\n <!-- ORDER -->\n @if (column.tools && orders[column.tools.id]) {\n <mat-icon\n (click)=\"updateOrder(column.tools.id)\"\n [style.cursor]=\"\n orders[column.tools.id].type === 'ORDER' || !orders[column.tools.id].current\n ? 'pointer'\n : 'default'\n \"\n >\n {{\n orders[column.tools.id].current === 'ASC'\n ? 'north'\n : orders[column.tools.id].current === 'DESC'\n ? 'south'\n : 'swap_vert'\n }}\n </mat-icon>\n }\n\n <!-- FILTER -->\n @if (column.tools && filters[column.tools.id]) {\n <mat-icon [style.cursor]=\"'pointer'\" (click)=\"updateFilter(column.tools.id)\">filter_alt</mat-icon>\n }\n </div>\n </th>\n }\n\n <!-- ACTION -->\n @if (hasAction) {\n <th></th>\n }\n </tr>\n </thead>\n\n <!-- BODY -->\n <tbody>\n @for (item of data; track $index; let dataIndex = $index) {\n <tr\n [style.color]=\"colors[dataIndex]\"\n [style.background-color]=\"\n viewConfig.alternateRows\n ? dataIndex % 2 === 1\n ? viewConfig.oddRowsBackgroundColor\n : viewConfig.evenRowsBackgroundColor\n : ''\n \"\n >\n <!-- ICON -->\n @if (hasIcon) {\n <td class=\"icon\" [style.border-color]=\"viewConfig.alternateRows ? '' : viewConfig.borderColor\">\n <mat-icon [style.color]=\"icons[$index].color\" [style.font-size]=\"viewConfig.iconSize\">\n {{ icons[$index].icon }}\n </mat-icon>\n </td>\n }\n\n <!-- DATA -->\n @for (column of ngxTable.columns; track $index; let columnIndex = $index) {\n <td [style.border-color]=\"viewConfig.alternateRows ? '' : viewConfig.borderColor\">\n <view-value\n [column]=\"column\"\n [item]=\"item\"\n [viewConfig]=\"viewConfig\"\n [isDeactive]=\"columnIndex === titleIndex && deactives.includes(dataIndex)\"\n ></view-value>\n </td>\n }\n\n <!-- ACTION -->\n @if (hasAction) {\n <td class=\"action\" [style.border-color]=\"viewConfig.alternateRows ? '' : viewConfig.borderColor\">\n <view-action\n [actions]=\"ngxTable.actions || []\"\n [item]=\"item\"\n [viewConfig]=\"viewConfig\"\n [isMobile]=\"false\"\n ></view-action>\n </td>\n }\n </tr>\n\n <!-- DESCRIPTION -->\n @if (descriptions[dataIndex]) {\n <tr\n [style.background-color]=\"\n viewConfig.alternateRows\n ? dataIndex % 2 === 1\n ? viewConfig.oddRowsBackgroundColor\n : viewConfig.evenRowsBackgroundColor\n : ''\n \"\n >\n @if (hasIcon) {\n <td class=\"description\"></td>\n }\n <td\n class=\"description\"\n [colSpan]=\"ngxTable.columns.length + (hasAction ? 1 : 0)\"\n [innerHTML]=\"descriptions[dataIndex] || '' | ngxHelperMultiLine\"\n ></td>\n </tr>\n } }\n </tbody>\n</table>\n", styles: ["table thead{z-index:1}table thead th{padding:1.25rem 1rem}table thead th .column{display:flex;align-items:center;column-gap:.5rem}table thead th .column mat-icon{font-size:100%}table thead th.active-filters{padding:0;text-align:right;border-bottom:1px solid transparent}table thead th.active-filters .toolbar{display:flex;align-items:center;flex-wrap:wrap;row-gap:.5rem;column-gap:.5rem;overflow:hidden;padding:.75rem}table thead th.active-filters .toolbar .item{display:flex;align-items:center;font-size:85%;border-radius:16px;border:1px solid transparent;white-space:nowrap}table thead th.active-filters .toolbar .item .title{cursor:pointer;padding:0 .75rem 0 .5rem}table thead th.active-filters .toolbar .item .value{cursor:pointer;padding-left:.5rem;font-weight:400;max-width:150px;overflow:hidden;text-overflow:ellipsis}table thead th.active-filters .toolbar .item .icon{display:flex;align-items:center;justify-content:center;cursor:pointer;padding:.25rem .5rem}table thead th.active-filters .toolbar .item .icon mat-icon{font-size:100%}table thead th.active-filters .toolbar .clear{display:flex;align-items:center;column-gap:.5rem;font-size:85%;border-radius:16px;border:1px solid transparent;white-space:nowrap;padding:.25rem .5rem;cursor:pointer}table thead th.active-filters .toolbar .clear mat-icon{font-size:100%}table tbody td{padding:.75rem 1rem;vertical-align:top;border-top:1px solid transparent}table tbody td.icon{padding-left:0}table tbody td.action{padding:.25rem 0 0}table tbody td.description{padding-top:0;font-size:85%;line-height:1.5;text-align:justify}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "pipe", type: NgxHelperMultiLinePipe, name: "ngxHelperMultiLine" }, { kind: "component", type: ViewActionComponent, selector: "view-action", inputs: ["actions", "item", "viewConfig", "isMobile"] }, { kind: "component", type: ViewValueComponent, selector: "view-value", inputs: ["column", "item", "viewConfig", "isDeactive", "isCard", "isCardTitle", "isCardSubTitle"] }], animations: [
1033
+ trigger('toolbar', [
1034
+ transition(':enter', [style({ opacity: 0, height: 0 }), animate('150ms', style({ opacity: 1, height: '*' }))]),
1035
+ ]),
1036
+ ] });
1037
+ }
1038
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: ViewTableComponent, decorators: [{
1039
+ type: Component,
1040
+ args: [{ selector: 'view-table', imports: [NgClass, MatIcon, NgxHelperMultiLinePipe, ViewActionComponent, ViewValueComponent], providers: [FilterService, ViewService], animations: [
1041
+ trigger('toolbar', [
1042
+ transition(':enter', [style({ opacity: 0, height: 0 }), animate('150ms', style({ opacity: 1, height: '*' }))]),
1043
+ ]),
1044
+ ], template: "<table [cellPadding]=\"0\" [cellSpacing]=\"0\" [width]=\"'100%'\" [border]=\"0\">\n <!-- HEADER -->\n\n <thead\n [style.color]=\"viewConfig.headerTextColor\"\n [style.background-color]=\"viewConfig.headerBackgroundColor\"\n [style.position]=\"viewConfig.stickyView?.headerTop ? 'sticky' : 'static'\"\n [style.top]=\"viewConfig.stickyView?.headerTop?.desktopView || undefined\"\n >\n <!-- ACTIVE FILTERS -->\n @if (activeFilters.length > 0) {\n <tr>\n <!-- ICON -->\n @if (hasIcon) {\n <th class=\"active-filters\" [style.border-color]=\"viewConfig.borderColor\"></th>\n }\n\n <!-- TOOLBAR -->\n <th\n class=\"active-filters\"\n [colSpan]=\"ngxTable.columns.length + (this.hasAction ? 1 : 0)\"\n [style.border-color]=\"viewConfig.borderColor\"\n >\n <div class=\"toolbar\" [@toolbar]>\n @for (item of activeFilters; track $index) {\n <div class=\"item\" [style.border-color]=\"viewConfig.borderColor\">\n <div class=\"title\" (click)=\"updateFilter(item.id)\">{{ item.title }}:</div>\n <div\n class=\"value\"\n (click)=\"updateFilter(item.id)\"\n [ngClass]=\"item.english ? viewConfig.enClass : ''\"\n >\n {{ item.value }}\n </div>\n <div class=\"icon\" (click)=\"clearFilter(item.id)\">\n <mat-icon>close</mat-icon>\n </div>\n </div>\n }\n\n <!-- CLEAR ALL -->\n @if (activeFilters.length > 2) {\n <div\n class=\"clear\"\n [style.border-color]=\"viewConfig.highlightText\"\n [style.color]=\"viewConfig.highlightText\"\n [style.background-color]=\"viewConfig.highlightBackground\"\n (click)=\"filterCleared.next()\"\n >\n <div class=\"title\">\u0644\u063A\u0648 \u0641\u06CC\u0644\u062A\u0631\u0647\u0627</div>\n <mat-icon>filter_alt_off</mat-icon>\n </div>\n }\n </div>\n </th>\n </tr>\n }\n\n <tr>\n <!-- ICON -->\n @if (hasIcon) {\n <th></th>\n }\n\n <!-- COLUMNS -->\n @for (column of ngxTable.columns; track $index) {\n <th [style.text-align]=\"(column.textAlign || 'RIGHT').toLowerCase()\">\n <div class=\"column\">\n <div class=\"title\">{{ column.title }}</div>\n\n <!-- ORDER -->\n @if (column.tools && orders[column.tools.id]) {\n <mat-icon\n (click)=\"updateOrder(column.tools.id)\"\n [style.cursor]=\"\n orders[column.tools.id].type === 'ORDER' || !orders[column.tools.id].current\n ? 'pointer'\n : 'default'\n \"\n >\n {{\n orders[column.tools.id].current === 'ASC'\n ? 'north'\n : orders[column.tools.id].current === 'DESC'\n ? 'south'\n : 'swap_vert'\n }}\n </mat-icon>\n }\n\n <!-- FILTER -->\n @if (column.tools && filters[column.tools.id]) {\n <mat-icon [style.cursor]=\"'pointer'\" (click)=\"updateFilter(column.tools.id)\">filter_alt</mat-icon>\n }\n </div>\n </th>\n }\n\n <!-- ACTION -->\n @if (hasAction) {\n <th></th>\n }\n </tr>\n </thead>\n\n <!-- BODY -->\n <tbody>\n @for (item of data; track $index; let dataIndex = $index) {\n <tr\n [style.color]=\"colors[dataIndex]\"\n [style.background-color]=\"\n viewConfig.alternateRows\n ? dataIndex % 2 === 1\n ? viewConfig.oddRowsBackgroundColor\n : viewConfig.evenRowsBackgroundColor\n : ''\n \"\n >\n <!-- ICON -->\n @if (hasIcon) {\n <td class=\"icon\" [style.border-color]=\"viewConfig.alternateRows ? '' : viewConfig.borderColor\">\n <mat-icon [style.color]=\"icons[$index].color\" [style.font-size]=\"viewConfig.iconSize\">\n {{ icons[$index].icon }}\n </mat-icon>\n </td>\n }\n\n <!-- DATA -->\n @for (column of ngxTable.columns; track $index; let columnIndex = $index) {\n <td [style.border-color]=\"viewConfig.alternateRows ? '' : viewConfig.borderColor\">\n <view-value\n [column]=\"column\"\n [item]=\"item\"\n [viewConfig]=\"viewConfig\"\n [isDeactive]=\"columnIndex === titleIndex && deactives.includes(dataIndex)\"\n ></view-value>\n </td>\n }\n\n <!-- ACTION -->\n @if (hasAction) {\n <td class=\"action\" [style.border-color]=\"viewConfig.alternateRows ? '' : viewConfig.borderColor\">\n <view-action\n [actions]=\"ngxTable.actions || []\"\n [item]=\"item\"\n [viewConfig]=\"viewConfig\"\n [isMobile]=\"false\"\n ></view-action>\n </td>\n }\n </tr>\n\n <!-- DESCRIPTION -->\n @if (descriptions[dataIndex]) {\n <tr\n [style.background-color]=\"\n viewConfig.alternateRows\n ? dataIndex % 2 === 1\n ? viewConfig.oddRowsBackgroundColor\n : viewConfig.evenRowsBackgroundColor\n : ''\n \"\n >\n @if (hasIcon) {\n <td class=\"description\"></td>\n }\n <td\n class=\"description\"\n [colSpan]=\"ngxTable.columns.length + (hasAction ? 1 : 0)\"\n [innerHTML]=\"descriptions[dataIndex] || '' | ngxHelperMultiLine\"\n ></td>\n </tr>\n } }\n </tbody>\n</table>\n", styles: ["table thead{z-index:1}table thead th{padding:1.25rem 1rem}table thead th .column{display:flex;align-items:center;column-gap:.5rem}table thead th .column mat-icon{font-size:100%}table thead th.active-filters{padding:0;text-align:right;border-bottom:1px solid transparent}table thead th.active-filters .toolbar{display:flex;align-items:center;flex-wrap:wrap;row-gap:.5rem;column-gap:.5rem;overflow:hidden;padding:.75rem}table thead th.active-filters .toolbar .item{display:flex;align-items:center;font-size:85%;border-radius:16px;border:1px solid transparent;white-space:nowrap}table thead th.active-filters .toolbar .item .title{cursor:pointer;padding:0 .75rem 0 .5rem}table thead th.active-filters .toolbar .item .value{cursor:pointer;padding-left:.5rem;font-weight:400;max-width:150px;overflow:hidden;text-overflow:ellipsis}table thead th.active-filters .toolbar .item .icon{display:flex;align-items:center;justify-content:center;cursor:pointer;padding:.25rem .5rem}table thead th.active-filters .toolbar .item .icon mat-icon{font-size:100%}table thead th.active-filters .toolbar .clear{display:flex;align-items:center;column-gap:.5rem;font-size:85%;border-radius:16px;border:1px solid transparent;white-space:nowrap;padding:.25rem .5rem;cursor:pointer}table thead th.active-filters .toolbar .clear mat-icon{font-size:100%}table tbody td{padding:.75rem 1rem;vertical-align:top;border-top:1px solid transparent}table tbody td.icon{padding-left:0}table tbody td.action{padding:.25rem 0 0}table tbody td.description{padding-top:0;font-size:85%;line-height:1.5;text-align:justify}\n"] }]
1045
+ }], ctorParameters: () => [{ type: ViewService }, { type: FilterService }], propDecorators: { ngxTable: [{
1046
+ type: Input,
1047
+ args: [{ required: true }]
1048
+ }], data: [{
1049
+ type: Input,
1050
+ args: [{ required: true }]
1051
+ }], viewConfig: [{
1052
+ type: Input,
1053
+ args: [{ required: true }]
1054
+ }], orderChanged: [{
1055
+ type: Output
1056
+ }], filterChanged: [{
1057
+ type: Output
1058
+ }], filterCleared: [{
1059
+ type: Output
1060
+ }] } });
1061
+
1062
+ const NGX_TABLE_CONFIG = new InjectionToken('NGX-TABLE-CONFIG');
1063
+ const provideNgxTableConfig = (config) => {
1064
+ const providers = [{ provide: NGX_TABLE_CONFIG, useValue: config }];
1065
+ return makeEnvironmentProviders(providers);
1066
+ };
1067
+
1068
+ class NgxTableComponent {
1069
+ activatedRoute;
1070
+ router;
1071
+ filterService;
1072
+ viewService;
1073
+ config;
1074
+ loading;
1075
+ ngxTable;
1076
+ data;
1077
+ pagination;
1078
+ filterChanged = new EventEmitter();
1079
+ isMobile = false;
1080
+ loaderClass;
1081
+ emptyClass;
1082
+ viewConfig;
1083
+ filter;
1084
+ hasFilter = false;
1085
+ constructor(activatedRoute, router, filterService, viewService, config) {
1086
+ this.activatedRoute = activatedRoute;
1087
+ this.router = router;
1088
+ this.filterService = filterService;
1089
+ this.viewService = viewService;
1090
+ this.config = config;
1091
+ }
1092
+ ngOnInit() {
1093
+ const queryParams = { ...this.activatedRoute.snapshot.queryParams };
1094
+ const page = !!this.ngxTable.route
1095
+ ? Helper.IS.number(+queryParams['ngx-table-page'])
1096
+ ? +queryParams['ngx-table-page']
1097
+ : 1
1098
+ : 1;
1099
+ const orders = this.viewService.getOrders(this.ngxTable);
1100
+ let order = undefined;
1101
+ Object.keys(orders).forEach((id) => {
1102
+ if (!orders[id].current)
1103
+ return;
1104
+ const type = orders[id].current;
1105
+ order = { id, type: type, param: `${id}:${type}` };
1106
+ });
1107
+ const filters = this.filterService.getFilters(this.ngxTable);
1108
+ const filter = {};
1109
+ Object.keys(filters).forEach((id) => {
1110
+ if (filters[id].value === undefined)
1111
+ return;
1112
+ const column = this.ngxTable.columns.find((column) => column.tools?.id === id);
1113
+ if (!column || !column.tools || !('filter' in column.tools) || !column.tools.filter)
1114
+ return;
1115
+ const param = column.tools.filter.toParam?.(filters[id].value) ||
1116
+ FilterInfo[column.tools.filter.type].methods.toParam(filters[id].value);
1117
+ filter[id] = { value: filters[id].value, param };
1118
+ });
1119
+ this.filter = { page, order, filter };
1120
+ this.filterChanged.next(this.filter);
1121
+ }
1122
+ ngOnChanges(changes) {
1123
+ this.ngxTable = {
1124
+ ...this.ngxTable,
1125
+ columns: this.ngxTable.columns.map((column) => ColumnInfo[column.type].methods.column(column)),
1126
+ };
1127
+ this.loaderClass = this.config?.cssClasses?.loader || 'ngx-table-loader';
1128
+ this.emptyClass = this.config?.cssClasses?.empty || 'ngx-table-empty';
1129
+ const getStickyView = (config) => {
1130
+ return {
1131
+ desktopView: typeof config === 'string' ? config : config.desktopView,
1132
+ mobileView: typeof config === 'string' ? config : config.mobileView,
1133
+ };
1134
+ };
1135
+ this.viewConfig = {
1136
+ alternateRows: !!this.config?.alternateRows,
1137
+ iconSize: `${this.config?.iconSize || 24}px`,
1138
+ enClass: this.config?.cssClasses?.en || 'ngx-table-en',
1139
+ deactiveClass: this.config?.cssClasses?.deactive || 'ngx-table-deactive',
1140
+ borderColor: this.config?.colors?.border || 'var(--outline-variant)',
1141
+ backgroundColor: this.config?.colors?.background || 'var(--background)',
1142
+ headerTextColor: this.config?.colors?.headerText || '',
1143
+ headerBackgroundColor: this.config?.colors?.headerBackground || 'var(--surface-container-highest)',
1144
+ oddRowsBackgroundColor: this.config?.colors?.oddRowsBackground || 'var(--background)',
1145
+ evenRowsBackgroundColor: this.config?.colors?.evenRowsBackground || 'var(--surface-container)',
1146
+ cardBackgroundColor: this.config?.colors?.cardBackground || 'var(--surface-container-high)',
1147
+ paginationBackgroundColor: this.config?.colors?.paginationBackground || 'var(--background)',
1148
+ highlightText: this.config?.colors?.highlightText || 'var(--secondary)',
1149
+ highlightBackground: this.config?.colors?.highlightBackground || 'var(--secondary-container)',
1150
+ inputText: this.config?.colors?.inputText || 'var(--on-surface)',
1151
+ inputBackground: this.config?.colors?.inputBackground || 'var(--surface-container-highest)',
1152
+ actionButtonSize: this.config?.action?.buttonSize || '90%',
1153
+ actionButtonColor: this.config?.action?.buttonColor || 'var(--primary)',
1154
+ actionMenuColor: this.config?.action?.buttonColor || '',
1155
+ actionWarnColor: this.config?.action?.warnColor || 'var(--error)',
1156
+ actionMenuTitle: this.config?.action?.menuTitle || 'امکانات',
1157
+ stickyView: this.config?.stickyView
1158
+ ? {
1159
+ headerTop: this.config.stickyView.headerTop
1160
+ ? getStickyView(this.config.stickyView.headerTop)
1161
+ : undefined,
1162
+ paginationBottom: this.config.stickyView.paginationBottom
1163
+ ? getStickyView(this.config.stickyView.paginationBottom)
1164
+ : undefined,
1165
+ }
1166
+ : undefined,
1167
+ };
1168
+ this.hasFilter = this.filter && Object.keys(this.filter).length !== 0;
1169
+ this.onResize();
1170
+ }
1171
+ onResize() {
1172
+ const mobileWidth = this.config?.mobileWidth || 600;
1173
+ this.isMobile = this.ngxTable.mobileView || window.innerWidth <= mobileWidth;
1174
+ }
1175
+ setQueryParams() {
1176
+ if (!this.ngxTable.route)
1177
+ return;
1178
+ const queryParams = { ...this.activatedRoute.snapshot.queryParams };
1179
+ const keys = Object.keys(queryParams);
1180
+ keys.forEach((id) => id.substring(0, 17) === 'ngx-table-filter-' && delete queryParams[id]);
1181
+ queryParams['ngx-table-page'] = this.filter.page !== 1 ? this.filter.page.toString() : undefined;
1182
+ queryParams['ngx-table-order'] = this.filter.order ? this.filter.order.param : undefined;
1183
+ Object.keys(this.filter.filter).forEach((id) => {
1184
+ const column = this.ngxTable.columns.find((column) => column.tools?.id === id);
1185
+ if (!column || !column.tools || !('filter' in column.tools) || !column.tools.filter)
1186
+ return;
1187
+ const param = FilterInfo[column.tools.filter.type].methods.query(this.filter.filter[id].value);
1188
+ queryParams[`ngx-table-filter-${id}`] = param;
1189
+ });
1190
+ this.router.navigate(this.ngxTable.route, { queryParams });
1191
+ }
1192
+ pageChanged(page) {
1193
+ this.filter = { ...this.filter, page };
1194
+ this.setQueryParams();
1195
+ this.filterChanged.next(this.filter);
1196
+ }
1197
+ orderChanged(order) {
1198
+ const param = `${order.id}:${order.type}`;
1199
+ this.filter = { ...this.filter, order: { ...order, param } };
1200
+ this.setQueryParams();
1201
+ this.filterChanged.next(this.filter);
1202
+ }
1203
+ filterItemChanged(filter) {
1204
+ const column = this.ngxTable.columns.find((column) => column.tools?.id === filter.id);
1205
+ if (!column || !column.tools || !('filter' in column.tools) || !column.tools.filter)
1206
+ return;
1207
+ if (filter.value === undefined)
1208
+ delete this.filter.filter[filter.id];
1209
+ else {
1210
+ const param = column.tools.filter.toParam?.(filter.value) ||
1211
+ FilterInfo[column.tools.filter.type].methods.toParam(filter.value);
1212
+ this.filter.filter[filter.id] = { value: filter.value, param };
1213
+ }
1214
+ this.setQueryParams();
1215
+ this.filterChanged.next(this.filter);
1216
+ }
1217
+ filterCleared() {
1218
+ this.filter = { ...this.filter, filter: {} };
1219
+ this.setQueryParams();
1220
+ this.filterChanged.next(this.filter);
1221
+ }
1222
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgxTableComponent, deps: [{ token: i1$1.ActivatedRoute }, { token: i1$1.Router }, { token: FilterService }, { token: ViewService }, { token: NGX_TABLE_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Component });
1223
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.3", type: NgxTableComponent, isStandalone: true, selector: "ngx-table", inputs: { loading: "loading", ngxTable: "ngxTable", data: "data", pagination: "pagination" }, outputs: { filterChanged: "filterChanged" }, host: { listeners: { "window:resize": "onResize($event)" } }, providers: [FilterService, ViewService], usesOnChanges: true, ngImport: i0, template: "@if (loading) {\n<div [ngClass]=\"loaderClass\"></div>\n}\n\n<!-- EMPTY -->\n@if (!loading && data.length === 0 && !hasFilter) {\n<div [ngClass]=\"emptyClass\" [dir]=\"'rtl'\">{{ ngxTable.type }} \u062B\u0628\u062A \u0646\u0634\u062F\u0647 \u0627\u0633\u062A.</div>\n}\n\n<!-- DATA -->\n@if (!loading && (data.length > 0 || hasFilter)) {\n<content>\n <!-- DESKTOP -->\n @if (!isMobile) {\n <view-table\n [ngxTable]=\"ngxTable\"\n [data]=\"data\"\n [viewConfig]=\"viewConfig\"\n (orderChanged)=\"orderChanged($event)\"\n (filterChanged)=\"filterItemChanged($event)\"\n (filterCleared)=\"filterCleared()\"\n ></view-table>\n }\n\n <!-- MOBILE -->\n @if (isMobile) {\n <view-card\n [ngxTable]=\"ngxTable\"\n [data]=\"data\"\n [viewConfig]=\"viewConfig\"\n (orderChanged)=\"orderChanged($event)\"\n (filterChanged)=\"filterItemChanged($event)\"\n (filterCleared)=\"filterCleared()\"\n ></view-card>\n }\n\n <!-- PAGINATION -->\n @if (pagination && pagination.page.total> 1) {\n <view-pagination\n [type]=\"ngxTable.type\"\n [pagination]=\"pagination\"\n [viewConfig]=\"viewConfig\"\n [isMobile]=\"isMobile\"\n [stickyBottom]=\"viewConfig.stickyView?.paginationBottom\"\n (pageChanged)=\"pageChanged($event)\"\n ></view-pagination>\n }\n\n <!-- EMPTY -->\n @if ( data.length === 0) {\n <div [ngClass]=\"emptyClass\" [dir]=\"'rtl'\">{{ ngxTable.type }} \u062B\u0628\u062A \u0646\u0634\u062F\u0647 \u0627\u0633\u062A.</div>\n }\n</content>\n}\n", styles: ["content{display:block;direction:rtl;position:relative}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: ViewCardComponent, selector: "view-card", inputs: ["ngxTable", "data", "viewConfig"], outputs: ["orderChanged", "filterChanged", "filterCleared"] }, { kind: "component", type: ViewPaginationComponent, selector: "view-pagination", inputs: ["type", "pagination", "viewConfig", "isMobile", "stickyBottom"], outputs: ["pageChanged"] }, { kind: "component", type: ViewTableComponent, selector: "view-table", inputs: ["ngxTable", "data", "viewConfig"], outputs: ["orderChanged", "filterChanged", "filterCleared"] }] });
1224
+ }
1225
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgxTableComponent, decorators: [{
1226
+ type: Component,
1227
+ args: [{ selector: 'ngx-table', host: { '(window:resize)': 'onResize($event)' }, imports: [NgClass, ViewCardComponent, ViewPaginationComponent, ViewTableComponent], providers: [FilterService, ViewService], template: "@if (loading) {\n<div [ngClass]=\"loaderClass\"></div>\n}\n\n<!-- EMPTY -->\n@if (!loading && data.length === 0 && !hasFilter) {\n<div [ngClass]=\"emptyClass\" [dir]=\"'rtl'\">{{ ngxTable.type }} \u062B\u0628\u062A \u0646\u0634\u062F\u0647 \u0627\u0633\u062A.</div>\n}\n\n<!-- DATA -->\n@if (!loading && (data.length > 0 || hasFilter)) {\n<content>\n <!-- DESKTOP -->\n @if (!isMobile) {\n <view-table\n [ngxTable]=\"ngxTable\"\n [data]=\"data\"\n [viewConfig]=\"viewConfig\"\n (orderChanged)=\"orderChanged($event)\"\n (filterChanged)=\"filterItemChanged($event)\"\n (filterCleared)=\"filterCleared()\"\n ></view-table>\n }\n\n <!-- MOBILE -->\n @if (isMobile) {\n <view-card\n [ngxTable]=\"ngxTable\"\n [data]=\"data\"\n [viewConfig]=\"viewConfig\"\n (orderChanged)=\"orderChanged($event)\"\n (filterChanged)=\"filterItemChanged($event)\"\n (filterCleared)=\"filterCleared()\"\n ></view-card>\n }\n\n <!-- PAGINATION -->\n @if (pagination && pagination.page.total> 1) {\n <view-pagination\n [type]=\"ngxTable.type\"\n [pagination]=\"pagination\"\n [viewConfig]=\"viewConfig\"\n [isMobile]=\"isMobile\"\n [stickyBottom]=\"viewConfig.stickyView?.paginationBottom\"\n (pageChanged)=\"pageChanged($event)\"\n ></view-pagination>\n }\n\n <!-- EMPTY -->\n @if ( data.length === 0) {\n <div [ngClass]=\"emptyClass\" [dir]=\"'rtl'\">{{ ngxTable.type }} \u062B\u0628\u062A \u0646\u0634\u062F\u0647 \u0627\u0633\u062A.</div>\n }\n</content>\n}\n", styles: ["content{display:block;direction:rtl;position:relative}\n"] }]
1228
+ }], ctorParameters: () => [{ type: i1$1.ActivatedRoute }, { type: i1$1.Router }, { type: FilterService }, { type: ViewService }, { type: undefined, decorators: [{
1229
+ type: Optional
1230
+ }, {
1231
+ type: Inject,
1232
+ args: [NGX_TABLE_CONFIG]
1233
+ }] }], propDecorators: { loading: [{
1234
+ type: Input,
1235
+ args: [{ required: true }]
1236
+ }], ngxTable: [{
1237
+ type: Input,
1238
+ args: [{ required: true }]
1239
+ }], data: [{
1240
+ type: Input,
1241
+ args: [{ required: true }]
1242
+ }], pagination: [{
1243
+ type: Input,
1244
+ args: [{ required: false }]
1245
+ }], filterChanged: [{
1246
+ type: Output
1247
+ }] } });
1248
+
1249
+ /*
1250
+ * Public API Surface of ngx-table-m3
1251
+ */
1252
+
1253
+ /**
1254
+ * Generated bundle index. Do not edit.
1255
+ */
1256
+
1257
+ export { NGX_TABLE_CONFIG, NgxTableComponent, provideNgxTableConfig };
1258
+ //# sourceMappingURL=webilix-ngx-table-m3.mjs.map