@acorex/layout 4.1.4 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. package/karma.conf.js +32 -0
  2. package/ng-package.json +9 -0
  3. package/package.json +11 -31
  4. package/src/lib/widget-board/editors/widget-size-editor/widget-size.editor.html +10 -0
  5. package/src/lib/widget-board/editors/widget-size-editor/widget-size.editor.ts +55 -0
  6. package/src/lib/widget-board/editors/widget-size-editor/widget-size.module.ts +19 -0
  7. package/src/lib/widget-board/widget-board.component.html +7 -0
  8. package/src/lib/widget-board/widget-board.component.scss +198 -0
  9. package/src/lib/widget-board/widget-board.component.ts +510 -0
  10. package/src/lib/widget-board/widget-board.module.ts +74 -0
  11. package/src/lib/widget-board/widget-config.component.html +16 -0
  12. package/src/lib/widget-board/widget-config.component.ts +99 -0
  13. package/src/lib/widget-board/widget-host.component.html +30 -0
  14. package/src/lib/widget-board/widget-host.component.ts +343 -0
  15. package/src/lib/widget-board/widget-save.component.html +43 -0
  16. package/src/lib/widget-board/widget-save.component.ts +88 -0
  17. package/src/lib/widget-board/widget.class.ts +178 -0
  18. package/{public-api.d.ts → src/public-api.ts} +0 -0
  19. package/src/test.ts +28 -0
  20. package/tsconfig.lib.json +23 -0
  21. package/tsconfig.lib.prod.json +6 -0
  22. package/tsconfig.spec.json +17 -0
  23. package/tslint.json +17 -0
  24. package/acorex-layout.d.ts +0 -5
  25. package/esm2020/acorex-layout.mjs +0 -5
  26. package/esm2020/lib/widget-board/editors/widget-size-editor/widget-size.editor.mjs +0 -46
  27. package/esm2020/lib/widget-board/editors/widget-size-editor/widget-size.module.mjs +0 -21
  28. package/esm2020/lib/widget-board/widget-board.component.mjs +0 -441
  29. package/esm2020/lib/widget-board/widget-board.module.mjs +0 -111
  30. package/esm2020/lib/widget-board/widget-config.component.mjs +0 -82
  31. package/esm2020/lib/widget-board/widget-host.component.mjs +0 -290
  32. package/esm2020/lib/widget-board/widget-save.component.mjs +0 -79
  33. package/esm2020/lib/widget-board/widget.class.mjs +0 -127
  34. package/esm2020/public-api.mjs +0 -7
  35. package/fesm2015/acorex-layout.mjs +0 -1166
  36. package/fesm2015/acorex-layout.mjs.map +0 -1
  37. package/fesm2020/acorex-layout.mjs +0 -1159
  38. package/fesm2020/acorex-layout.mjs.map +0 -1
  39. package/lib/widget-board/editors/widget-size-editor/widget-size.editor.d.ts +0 -19
  40. package/lib/widget-board/editors/widget-size-editor/widget-size.module.d.ts +0 -10
  41. package/lib/widget-board/widget-board.component.d.ts +0 -61
  42. package/lib/widget-board/widget-board.module.d.ts +0 -18
  43. package/lib/widget-board/widget-config.component.d.ts +0 -23
  44. package/lib/widget-board/widget-host.component.d.ts +0 -51
  45. package/lib/widget-board/widget-save.component.d.ts +0 -19
  46. package/lib/widget-board/widget.class.d.ts +0 -56
@@ -0,0 +1,30 @@
1
+ <div class='widget-container'>
2
+ <div class="widget-config-overlay" *ngIf="!isConfigured" (click)="handleConfig($event)">
3
+ <div class="widget-title">{{config.title}}</div>
4
+ <div class="widget-config-box">
5
+ <div class="config-title">{{ 'widget-board.configure' | trans}}</div>
6
+ <div class="config-icon"><i class="fas fa-cogs fa-5x" aria-hidden="true"></i></div>
7
+ </div>
8
+ </div>
9
+ <div class='widget-edit-overlay'>
10
+ <div class='widget-edit-menu'>
11
+ <button class="widget-edit-menu-button" (click)="handleConfig($event)"
12
+ (mousedown)="$event.stopPropagation()" *ngIf="_hasProps" (mouseup)="$event.stopPropagation()">
13
+ <i class="far fa-cogs" aria-hidden="true"></i>
14
+ </button>
15
+ <button class="widget-edit-menu-button" (click)="remove($event)" (mousedown)="$event.stopPropagation()"
16
+ (mouseup)="$event.stopPropagation()">
17
+ <i class="far fa-times" aria-hidden="true"></i>
18
+ </button>
19
+ </div>
20
+
21
+ </div>
22
+ <div class="widget-options-menu" *ngIf="_hasMenu">
23
+ <ax-menu [items]='configMenuItem' direction="horizontal"></ax-menu>
24
+ </div>
25
+ <!-- <ax-loading-panel [visible]="isBusy">
26
+ </ax-loading-panel> -->
27
+ <div class="widget-content">
28
+ <ng-container #vc></ng-container>
29
+ </div>
30
+ </div>
@@ -0,0 +1,343 @@
1
+ import {
2
+ Component,
3
+ ViewEncapsulation, Input,
4
+ ElementRef, HostBinding, ComponentFactoryResolver, ViewChild,
5
+ ViewContainerRef, Output, EventEmitter, ChangeDetectionStrategy,
6
+ ChangeDetectorRef, ComponentRef
7
+ } from '@angular/core';
8
+ import { AXWidgetConfig, AXWidgetComponent, AXWidgetConfigChanged, AXWidgetConfigSavedEvent } from './widget.class';
9
+ import { AXObjectUtil, AXRenderService } from '@acorex/core';
10
+ import { AXPopupService, AXPropertyDecorators, AXPropertyDecorator, AXLoadingService } from '@acorex/components';
11
+ import { AXWidgetConfigComponent } from './widget-config.component';
12
+ import { AXMenuItem } from '@acorex/core';
13
+ import { AXTranslator } from '@acorex/core';
14
+ import { AXWidgetSaveComponent } from './widget-save.component';
15
+
16
+
17
+
18
+
19
+
20
+ @Component({
21
+ selector: 'ax-widget-host',
22
+ templateUrl: "./widget-host.component.html",
23
+ host: { class: 'ax widget-host', tabindex: '0' },
24
+ encapsulation: ViewEncapsulation.None,
25
+ changeDetection: ChangeDetectionStrategy.OnPush
26
+ })
27
+
28
+ export class AXWidgetHostComponent {
29
+
30
+ private _widget: AXWidgetComponent;
31
+ public get widget(): AXWidgetComponent {
32
+ return this._widget;
33
+ }
34
+
35
+ _hasProps: boolean = false;
36
+
37
+
38
+ _hasMenu: boolean = false;
39
+
40
+ @Input()
41
+ provideValue: (e: any) => any;
42
+
43
+
44
+ get element(): HTMLDivElement {
45
+ return this.ref.nativeElement;
46
+ }
47
+
48
+
49
+ configMenuItem: AXMenuItem[] = [
50
+ {
51
+ icon: 'far fa-ellipsis-h',
52
+ items: []
53
+ }
54
+ ];
55
+
56
+
57
+ @Output()
58
+ onRemove: EventEmitter<AXWidgetHostComponent> = new EventEmitter<AXWidgetHostComponent>();
59
+
60
+ @Output()
61
+ onConfigChanged: EventEmitter<AXWidgetConfigChanged> = new EventEmitter<AXWidgetConfigChanged>();
62
+
63
+
64
+ @Output()
65
+ onResized: EventEmitter<AXWidgetConfigChanged> = new EventEmitter<AXWidgetConfigChanged>();
66
+
67
+ @Output()
68
+ onSave: EventEmitter<AXWidgetConfigSavedEvent> = new EventEmitter<AXWidgetConfigSavedEvent>();
69
+
70
+ @Input()
71
+ config: AXWidgetConfig;
72
+
73
+ @ViewChild('vc', { read: ViewContainerRef })
74
+ vc: ViewContainerRef;
75
+
76
+ private componentRef: ComponentRef<any>;
77
+ //private isLoading: boolean = true;
78
+
79
+ // get isBusy() {
80
+ // return this._widget?.isBusy || this.isLoading;
81
+ // }
82
+
83
+
84
+ private _loadingId: number;
85
+
86
+ private _isLoading: boolean = false;
87
+ public get isLoading(): boolean {
88
+ return this._isLoading;
89
+ }
90
+ public set isLoading(v: boolean) {
91
+ this._isLoading = v;
92
+ if (this._loadingId && !v) {
93
+ this.loadingService.hide(this._loadingId);
94
+ this._loadingId = null;
95
+ }
96
+ if (v) {
97
+ this._loadingId = this.loadingService.show(this.ref.nativeElement);
98
+ }
99
+ }
100
+
101
+
102
+ get isConfigured(): boolean {
103
+ return this._widget?.isConfigured || false;
104
+ }
105
+
106
+
107
+ constructor(
108
+ private ref: ElementRef<HTMLDivElement>,
109
+ private componentFactoryResolver: ComponentFactoryResolver,
110
+ private rendererService: AXRenderService,
111
+ private cdr: ChangeDetectorRef,
112
+ private popup: AXPopupService,
113
+ private loadingService: AXLoadingService
114
+
115
+ ) {
116
+
117
+ }
118
+
119
+
120
+ ngOnInit() {
121
+ this.isLoading = true;
122
+ }
123
+
124
+
125
+ async ngAfterViewInit() {
126
+ let component: any;
127
+ if (typeof this.config.component === 'string') {
128
+ const route = await this.rendererService.findLoadedComponentByRoute(this.config.component, 20);
129
+ component = route?.component;
130
+ }
131
+ else if (typeof this.config.component === 'function') {
132
+ component = this.config.component;
133
+ }
134
+ if (component == null) {
135
+ console.error(`Invalid Widget Component!`, this.config);
136
+ this.onRemove.emit(this);
137
+ return;
138
+ }
139
+
140
+ const widgetFactory = this.componentFactoryResolver.resolveComponentFactory(component);
141
+ this.componentRef = this.vc.createComponent(widgetFactory);
142
+ this._widget = this.componentRef.instance as AXWidgetComponent;
143
+ this._widget.provideValue = this.provideValue;
144
+ if (this._widget.onBusyChanged) {
145
+ this._widget.onBusyChanged.subscribe((d) => {
146
+ if (!this._widget.widgetSize) {
147
+ this._widget.setValue('widgetSize', [this.sizeX, this.sizeY]);
148
+ }
149
+ else {
150
+ this.setSizeFromOptions();
151
+ }
152
+ this.isLoading = d.value;
153
+ this.cdr.detectChanges();
154
+ });
155
+ }
156
+ if (this._widget.onConfiguredChanged) {
157
+ this._widget.onConfiguredChanged.subscribe(() => {
158
+ this.setSizeFromOptions();
159
+ });
160
+ }
161
+ //
162
+ if (this.config.options) {
163
+ Object.assign(this._widget, this.config.options);
164
+ }
165
+ this._hasProps = AXPropertyDecorators.getProperties(this._widget).length > 0;
166
+
167
+ this.isLoading = false;
168
+ this.config['__meta__'].instance = this;
169
+ this._widget['__meta__'] = {};
170
+ this._widget['__meta__'].config = this.config;
171
+ //
172
+ this.configMenuItem[0].items.push({
173
+ name: 'refresh',
174
+ icon: 'far fa-undo',
175
+ text: AXTranslator.get('common.refresh'),
176
+ onClick: () => {
177
+ this?.widget?.refresh();
178
+ }
179
+ });
180
+ //
181
+ if (this._hasProps) {
182
+ this.configMenuItem[0].items.push({
183
+ name: 'configs',
184
+ icon: 'far fa-cogs',
185
+ text: AXTranslator.get('common.configs'),
186
+ onClick: () => {
187
+ this.openConfigDialog();
188
+ }
189
+ });
190
+ }
191
+ this.configMenuItem[0].items.push({
192
+ name: 'save',
193
+ icon: 'far fa-save',
194
+ text: AXTranslator.get('common.save-as'),
195
+ onClick: () => {
196
+ this.openSaveDialog();
197
+ }
198
+ });
199
+ if (true) {
200
+ this.configMenuItem[0].items.push({
201
+ name: 'remove',
202
+ icon: 'far fa-times',
203
+ style: 'ax danger blank',
204
+ text: AXTranslator.get('common.remove'),
205
+ onClick: () => {
206
+ this.onRemove.emit(this);
207
+ }
208
+ });
209
+ }
210
+ this._hasMenu = this.configMenuItem[0].items.length > 0;
211
+ this.cdr.detectChanges();
212
+ }
213
+
214
+ @HostBinding('attr.data-size-x')
215
+ @Input()
216
+ sizeX: number = 1;
217
+
218
+ @HostBinding('attr.data-size-y')
219
+ @Input()
220
+ sizeY: number = 1;
221
+
222
+ @HostBinding('attr.data-col')
223
+ @Input()
224
+ col: number = 1;
225
+
226
+
227
+ @HostBinding('attr.data-row')
228
+ @Input()
229
+ row: number = 1;
230
+
231
+
232
+ private setSizeFromOptions() {
233
+ this._widget.getValue('widgetSize').then(c => {
234
+ const oldSizeX = this.sizeX;
235
+ const oldSizeY = this.sizeY;
236
+ if (c && Array.isArray(c) && (oldSizeX !== c[0] || oldSizeY !== c[1])) {
237
+ this.config.sizeX = this.sizeX = c[0];
238
+ this.config.sizeY = this.sizeY = c[1];
239
+ this.onResized.emit({
240
+ component: this._widget,
241
+ config: this.config
242
+ });
243
+ }
244
+ this.cdr.detectChanges();
245
+ });
246
+ }
247
+
248
+ remove(e: MouseEvent) {
249
+ e.preventDefault();
250
+ e.stopPropagation();
251
+ this.onRemove.emit(this);
252
+ return false;
253
+ }
254
+
255
+ handleConfig(e: MouseEvent) {
256
+ e.preventDefault();
257
+ e.stopPropagation();
258
+ this.openConfigDialog();
259
+ return false;
260
+ }
261
+
262
+ private openConfigDialog() {
263
+ const ppp = this.getMergedProps();
264
+ this.popup.open(AXWidgetConfigComponent, {
265
+ title: AXTranslator.get('common.configs'),
266
+ size: 'sm',
267
+ data: {
268
+ props: ppp.map(c => ({ property: c.options, value: this._widget[c.options.name] })),
269
+ widget: this.widget
270
+ }
271
+ }).then(c => {
272
+ if (c.data) {
273
+ if (!this.config.options) {
274
+ this.config.options = {};
275
+ }
276
+ c.data.forEach(p => {
277
+ this._widget.setValue(p.property.name, p.value);
278
+ this.config.options[p.property.name] = p.value;
279
+ });
280
+ this.emitConfigChanged();
281
+ this._widget.redraw();
282
+ this.cdr.detectChanges();
283
+ }
284
+ });
285
+ }
286
+
287
+ private openSaveDialog() {
288
+ const ppp = this.getMergedProps();
289
+ this.popup.open(AXWidgetSaveComponent, {
290
+ title: AXTranslator.get('common.save-as'),
291
+ size: 'sm',
292
+ data: {
293
+ config: this.config,
294
+ props: ppp.map(c => ({ property: c.options, value: this._widget[c.options.name] }))
295
+ }
296
+ }).then(c => {
297
+ if (c.data) {
298
+ this.onSave.emit({
299
+ component: this._widget,
300
+ data: c.data
301
+ });
302
+ }
303
+ });
304
+ }
305
+
306
+
307
+
308
+ handleOptionClick(e: MouseEvent) {
309
+ e.preventDefault();
310
+ e.stopPropagation();
311
+ this.openConfigDialog();
312
+ return false;
313
+ }
314
+
315
+ ngOnDestroy() {
316
+ this.vc.clear();
317
+ if (this.componentRef) {
318
+ this.componentRef.destroy();
319
+ }
320
+ }
321
+
322
+ private getMergedProps(): AXPropertyDecorator[] {
323
+ const ppp = AXObjectUtil.deepCopy(AXPropertyDecorators.getProperties(this._widget)) as AXPropertyDecorator[];
324
+ for (const key in this.config.props) {
325
+ if (Object.prototype.hasOwnProperty.call(this.config.props, key)) {
326
+ const newP = this.config.props[key];
327
+ const existPropDec = ppp.find(p => p.property === key);
328
+ if (existPropDec) {
329
+ Object.assign(existPropDec.options, newP);
330
+ }
331
+ }
332
+ }
333
+ return ppp;
334
+ }
335
+
336
+ private emitConfigChanged() {
337
+ this.onConfigChanged.emit({
338
+ component: this._widget,
339
+ config: this.config
340
+ });
341
+ }
342
+
343
+ }
@@ -0,0 +1,43 @@
1
+ <ax-page>
2
+ <ax-page-content>
3
+ <div class="container">
4
+ <div class="row">
5
+ <div class="col-12">
6
+ <ax-form-group>
7
+ <ax-label>{{'common.title' | trans}}</ax-label>
8
+ <ax-text-box [(value)]="data.title"></ax-text-box>
9
+ </ax-form-group>
10
+ </div>
11
+ </div>
12
+ <div class="row">
13
+ <div class="col-12">
14
+ <ax-form-group>
15
+ <ax-label>{{'common.description' | trans}}</ax-label>
16
+ <ax-text-area [(value)]="data.description"></ax-text-area>
17
+ </ax-form-group>
18
+ </div>
19
+ </div>
20
+ <!-- <div class="row">
21
+ <div class="col-12">
22
+ <ax-form-group>
23
+ <ax-label>{{'common.uniquename' | trans}}</ax-label>
24
+ <ax-text-box></ax-text-box>
25
+ </ax-form-group>
26
+ </div>
27
+ </div> -->
28
+ <div class="row" style="margin-block-end: var(--ax-size-md);margin-block-start: var(--ax-size-md);">
29
+ <div class="col-12">
30
+ <ax-fieldset caption="{{'widget-board.configurable-props' | trans}}">
31
+ <div class="row" *ngFor="let prop of displayProps">
32
+ <div class="col-12" style="margin-block-end: var(--ax-size-sm)">
33
+ <ax-check-box [(value)]="prop.allow" label="{{ prop.title | trans }}">
34
+
35
+ </ax-check-box>
36
+ </div>
37
+ </div>
38
+ </ax-fieldset>
39
+ </div>
40
+ </div>
41
+ </div>
42
+ </ax-page-content>
43
+ </ax-page>
@@ -0,0 +1,88 @@
1
+ import {
2
+ Component,
3
+ ViewEncapsulation,
4
+ ChangeDetectionStrategy,
5
+
6
+ } from '@angular/core';
7
+ import { AXWidgetConfig, AXWidgetSaveAsData } from './widget.class';
8
+ import { AXButtonItem, AXHtmlUtil, AXObjectUtil, AXTranslator } from '@acorex/core';
9
+ import { AXPropertyConfig, AXMenuItemClickEvent, AXBasePopupPageComponent } from '@acorex/components';
10
+
11
+
12
+
13
+ @Component({
14
+ templateUrl: "./widget-save.component.html",
15
+ encapsulation: ViewEncapsulation.None,
16
+ changeDetection: ChangeDetectionStrategy.OnPush,
17
+ })
18
+ export class AXWidgetSaveComponent extends AXBasePopupPageComponent {
19
+ config: AXWidgetConfig;
20
+ props: AXPropertyConfig[] = [];
21
+ displayProps: { name: string, title: string, allow: boolean }[];
22
+
23
+ data: AXWidgetSaveAsData;
24
+
25
+ getFooterButtons(): AXButtonItem[] {
26
+ return [
27
+ {
28
+ name: 'okay',
29
+ submitBehavior: true,
30
+ text: AXTranslator.get('common.confirm'),
31
+ style: 'ax success'
32
+ },
33
+ {
34
+ name: 'cancel',
35
+ cancelBehavior: true,
36
+ text: AXTranslator.get('common.cancel'),
37
+ style: 'ax light'
38
+ }
39
+ ];
40
+ }
41
+
42
+ ngOnInit() {
43
+ const titleProp = this.props.find(c => c.property.name === 'title' || c.property.name === 'name');
44
+ const title = titleProp?.value || this.config.title;
45
+ const pp: any = {};
46
+ this.props?.forEach(c => {
47
+ pp[c.property.name] = c.property;
48
+ });
49
+ this.data = {
50
+ component: this.config.component,
51
+ title,
52
+ uniqueName: `${this.config.uniqueName}-${AXHtmlUtil.getUID()}`,
53
+ options: AXObjectUtil.deepJSONClone(this.config.options),
54
+ props: AXObjectUtil.deepJSONClone(pp)
55
+ };
56
+ this.displayProps = this.props
57
+ .filter(c => c.property.visible !== false)
58
+ .sort((a, b) => a.property.order - b.property.order)
59
+ .map(c => ({
60
+ name: c.property.name,
61
+ title: c.property.title,
62
+ allow: true
63
+ }));
64
+ }
65
+
66
+
67
+
68
+ onFooterButtonClick(e: AXMenuItemClickEvent) {
69
+ if (e.name === 'cancel') {
70
+ this.close();
71
+ }
72
+ if (e.name === 'okay') {
73
+ this.props.forEach(p => {
74
+ const pp = this.displayProps.find(c => c.name === p.property.name);
75
+ if (pp == null || !pp.allow) {
76
+ let ppp = this.data.props[p.property.name];
77
+ if (ppp) {
78
+ ppp.visible = false;
79
+ }
80
+ else {
81
+ ppp = { visible: false };
82
+ }
83
+ }
84
+ });
85
+ this.close(this.data);
86
+ }
87
+ }
88
+ }
@@ -0,0 +1,178 @@
1
+ import { EventEmitter, Injectable } from '@angular/core';
2
+ import { AXValueEvent, AXBaseEvent, propertyEditor, AXDataEvent } from '@acorex/components';
3
+ import { AXHtmlUtil, AXTranslator } from '@acorex/core';
4
+
5
+ export interface AXWidgetConfig {
6
+ uniqueName: string;
7
+ component: any;
8
+ title: string;
9
+ sizeX: number;
10
+ sizeY: number;
11
+ col?: number;
12
+ row?: number;
13
+ options?: any;
14
+ props?: any;
15
+ }
16
+
17
+ export interface AXWidgetConfigChanged extends AXBaseEvent {
18
+ config: AXWidgetConfig;
19
+ }
20
+
21
+
22
+
23
+ export interface AXWidgetBoardConfigChanged extends AXBaseEvent {
24
+
25
+ }
26
+
27
+ export interface AXWidgetConfigSavedEvent extends AXDataEvent<AXWidgetSaveAsData> {
28
+
29
+ }
30
+
31
+
32
+ export interface AXWidgetSaveAsData {
33
+ title?: string;
34
+ description?: string;
35
+ icon?: string;
36
+ group?: string;
37
+ //
38
+ uniqueName: string;
39
+ component: any;
40
+ options?: any;
41
+ props?: any;
42
+ }
43
+
44
+ // @dynamic
45
+ // TODO: Add Angular decorator.
46
+ @Injectable()
47
+ export abstract class AXWidgetComponent {
48
+
49
+ readonly uid: string = AXHtmlUtil.getUID();
50
+ provideValue: (e: any) => any;
51
+
52
+ onBusyChanged: EventEmitter<AXValueEvent<boolean>> = new EventEmitter<AXValueEvent<boolean>>();
53
+
54
+ private _isBusy: boolean = true;
55
+ public get isBusy(): boolean {
56
+ return this._isBusy;
57
+ }
58
+ public set isBusy(v: boolean) {
59
+ if (v !== this._isBusy) {
60
+ const eventData: AXValueEvent<boolean> = {
61
+ component: this,
62
+ oldValue: this._isBusy,
63
+ value: v
64
+ };
65
+ this._isBusy = v;
66
+ this.onBusyChanged.emit(eventData);
67
+ }
68
+ }
69
+
70
+ @propertyEditor({
71
+ editorClass: 'ax/editors/widget-size',
72
+ title: 'common.size',
73
+ visible: false,
74
+ order: -99,
75
+ })
76
+ widgetSize: number[];
77
+
78
+ @propertyEditor({
79
+ editorClass: 'ax/editors/select',
80
+ title: 'common.refresh-rate',
81
+ visible: true,
82
+ order: -98,
83
+ editorOptions: {
84
+ items: () => {
85
+ return [1, 2, 3, 5, 10, 20, 30, 60].map(c => ({
86
+ id: 60000 * c,
87
+ text: AXTranslator.get('dateTime.duration.format_minute').replace('{0}', c.toString())
88
+ }));
89
+ },
90
+ allowNull: false,
91
+ allowSearch: false,
92
+ selectionDataMode: 'value',
93
+ selectionMode: 'single',
94
+ valueField: 'id',
95
+ }
96
+ })
97
+ refreshRate: any = [{
98
+ id: 60000 * 5,
99
+ text: AXTranslator.get('dateTime.duration.format_minute').replace('{0}', '5')
100
+ }];
101
+
102
+ // ???
103
+ getRefreshRate() {
104
+ return Array.isArray(this.refreshRate) && this.refreshRate.length ? this.refreshRate[0].id : this.refreshRate;
105
+ }
106
+
107
+ private intervalId: number;
108
+
109
+ constructor() {
110
+ this.onConfiguredChanged.subscribe(() => {
111
+ if (this.isConfigured === true && this.getRefreshRate()) {
112
+ this.restartRefreshTimer();
113
+ }
114
+ else {
115
+ this.stopRefreshTimer();
116
+ }
117
+ });
118
+ }
119
+
120
+
121
+ private startRefreshTimer() {
122
+ this.intervalId = window.setInterval(this.refresh.bind(this), this.getRefreshRate());
123
+ }
124
+
125
+ private stopRefreshTimer() {
126
+ window.clearInterval(this.intervalId);
127
+ }
128
+
129
+ private restartRefreshTimer() {
130
+ this.stopRefreshTimer();
131
+ this.startRefreshTimer();
132
+ }
133
+
134
+ ngOnDestroy() {
135
+ this.stopRefreshTimer();
136
+ }
137
+
138
+ public redraw() {
139
+
140
+ }
141
+
142
+ public refresh() {
143
+ this.restartRefreshTimer();
144
+ }
145
+
146
+ onConfiguredChanged: EventEmitter<void> = new EventEmitter<void>();
147
+
148
+ get isConfigured(): boolean {
149
+ return true;
150
+ }
151
+
152
+ public setValue(name: string, value?: any) {
153
+ this[name] = value;
154
+ this.onConfiguredChanged.emit();
155
+ }
156
+
157
+ public getValue(name: string): Promise<any> {
158
+ const val = this[name];
159
+ const config = this['__meta__'].config;
160
+ const runtime = config.props[name]?.runtime;
161
+ if (runtime && this.provideValue) {
162
+ const res = this.provideValue({
163
+ name,
164
+ value: val,
165
+ uniqueName: config.uniqueName,
166
+ options: config.options,
167
+ });
168
+ if (this.provideValue instanceof Promise) {
169
+ return res;
170
+ }
171
+ else {
172
+ return Promise.resolve(res);
173
+ }
174
+ }
175
+ return Promise.resolve(val);
176
+ }
177
+
178
+ }
File without changes