@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.
- package/README.md +6 -0
- package/fesm2022/webilix-ngx-table-m3.mjs +1258 -0
- package/fesm2022/webilix-ngx-table-m3.mjs.map +1 -0
- package/index.d.ts +5 -0
- package/lib/columns/column.action.d.ts +24 -0
- package/lib/columns/column.info.d.ts +9 -0
- package/lib/columns/column.interface.d.ts +46 -0
- package/lib/columns/date/column-date.component.d.ts +10 -0
- package/lib/columns/date/column-date.interface.d.ts +10 -0
- package/lib/columns/duration/column-duration.component.d.ts +10 -0
- package/lib/columns/duration/column-duration.interface.d.ts +9 -0
- package/lib/columns/index.d.ts +13 -0
- package/lib/columns/mobile/column-mobile.component.d.ts +10 -0
- package/lib/columns/mobile/column-mobile.interface.d.ts +9 -0
- package/lib/columns/number/column-number.component.d.ts +10 -0
- package/lib/columns/number/column-number.interface.d.ts +9 -0
- package/lib/columns/text/column-text.component.d.ts +10 -0
- package/lib/columns/text/column-text.interface.d.ts +8 -0
- package/lib/filters/date/filter-date.component.d.ts +13 -0
- package/lib/filters/date/filter-date.interface.d.ts +16 -0
- package/lib/filters/filter.component.d.ts +35 -0
- package/lib/filters/filter.info.d.ts +8 -0
- package/lib/filters/filter.interface.d.ts +24 -0
- package/lib/filters/filter.service.d.ts +18 -0
- package/lib/filters/index.d.ts +10 -0
- package/lib/filters/multi-select/filter-multi-select.component.d.ts +14 -0
- package/lib/filters/multi-select/filter-multi-select.interface.d.ts +19 -0
- package/lib/filters/search/filter-search.component.d.ts +20 -0
- package/lib/filters/search/filter-search.interface.d.ts +20 -0
- package/lib/filters/select/filter-select.component.d.ts +13 -0
- package/lib/filters/select/filter-select.interface.d.ts +19 -0
- package/lib/ngx-table.component.d.ts +37 -0
- package/lib/ngx-table.config.d.ts +45 -0
- package/lib/ngx-table.interface.d.ts +43 -0
- package/lib/views/action/view-action.component.d.ts +27 -0
- package/lib/views/card/toolbar/view-card-toolbar.component.d.ts +23 -0
- package/lib/views/card/view-card.component.d.ts +38 -0
- package/lib/views/index.d.ts +4 -0
- package/lib/views/pagination/view-pagination.component.d.ts +26 -0
- package/lib/views/table/view-table.component.d.ts +42 -0
- package/lib/views/value/view-value.component.d.ts +60 -0
- package/lib/views/view.interface.d.ts +41 -0
- package/lib/views/view.service.d.ts +30 -0
- package/package.json +47 -0
- 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
|