@vgip/meta-ui 2.1.3 → 2.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/fesm2022/vgip-meta-ui.mjs +6092 -0
  2. package/fesm2022/vgip-meta-ui.mjs.map +1 -0
  3. package/index.d.ts +709 -0
  4. package/package.json +15 -3
  5. package/.eslintrc.json +0 -57
  6. package/karma.conf.js +0 -35
  7. package/ng-package.json +0 -10
  8. package/src/lib/common/fieldNormalizer/boolean.ts +0 -11
  9. package/src/lib/common/fieldNormalizer/datetime.ts +0 -8
  10. package/src/lib/common/fieldNormalizer/index.ts +0 -171
  11. package/src/lib/common/fieldNormalizer/number.ts +0 -13
  12. package/src/lib/common/fieldNormalizer/options.ts +0 -48
  13. package/src/lib/common/fieldNormalizer/radio.ts +0 -29
  14. package/src/lib/common/fieldNormalizer/reference.ts +0 -32
  15. package/src/lib/common/fieldNormalizer/richtext.ts +0 -15
  16. package/src/lib/common/fieldNormalizer/string.ts +0 -23
  17. package/src/lib/common/fieldNormalizer/text.ts +0 -17
  18. package/src/lib/common/fieldNormalizer/uniqueNameFilter.ts +0 -21
  19. package/src/lib/common/metaAutofocus.directive.ts +0 -31
  20. package/src/lib/common/metaContext.resolver.ts +0 -25
  21. package/src/lib/common/metaIcons.pipe.spec.ts +0 -15
  22. package/src/lib/common/metaIcons.pipe.ts +0 -29
  23. package/src/lib/common/metaModel.pipe.ts +0 -19
  24. package/src/lib/common/metaNormalizer.ts +0 -366
  25. package/src/lib/common/metaStripHtml.pipe.ts +0 -18
  26. package/src/lib/common/utils/colorThemes.ts +0 -86
  27. package/src/lib/common/utils/indexedDbStore/index.ts +0 -244
  28. package/src/lib/common/utils/indexedDbStore/indexedDbStore.spec.ts +0 -149
  29. package/src/lib/common/utils/relativeTimeBuilder.ts +0 -49
  30. package/src/lib/common/utils/resourceCardLabel.ts +0 -25
  31. package/src/lib/common/utils/smartProp.spec.ts +0 -24
  32. package/src/lib/common/utils/smartProp.ts +0 -28
  33. package/src/lib/common/utils/templateBuilder.ts +0 -99
  34. package/src/lib/field.scss +0 -207
  35. package/src/lib/fieldAbstract.ts +0 -327
  36. package/src/lib/fieldBoolean/index.ts +0 -55
  37. package/src/lib/fieldBoolean/style.scss +0 -22
  38. package/src/lib/fieldBoolean/test.spec.ts +0 -43
  39. package/src/lib/fieldBoolean/view.html +0 -30
  40. package/src/lib/fieldComposite/index.ts +0 -86
  41. package/src/lib/fieldComposite/style.scss +0 -6
  42. package/src/lib/fieldComposite/test.spec.ts +0 -43
  43. package/src/lib/fieldComposite/view.html +0 -9
  44. package/src/lib/fieldDatetime/index.ts +0 -359
  45. package/src/lib/fieldDatetime/style.scss +0 -81
  46. package/src/lib/fieldDatetime/test.spec.ts +0 -43
  47. package/src/lib/fieldDatetime/view.html +0 -26
  48. package/src/lib/fieldHidden/index.ts +0 -15
  49. package/src/lib/fieldHidden/view.html +0 -0
  50. package/src/lib/fieldInput/index.ts +0 -477
  51. package/src/lib/fieldInput/style.scss +0 -128
  52. package/src/lib/fieldInput/test.spec.ts +0 -43
  53. package/src/lib/fieldInput/view.html +0 -81
  54. package/src/lib/fieldList/index.ts +0 -73
  55. package/src/lib/fieldList/style.scss +0 -26
  56. package/src/lib/fieldList/test.spec.ts +0 -43
  57. package/src/lib/fieldList/view.html +0 -25
  58. package/src/lib/fieldRadio/index.ts +0 -93
  59. package/src/lib/fieldRadio/style.scss +0 -32
  60. package/src/lib/fieldRadio/test.spec.ts +0 -43
  61. package/src/lib/fieldRadio/view.html +0 -24
  62. package/src/lib/fieldReference/index.ts +0 -871
  63. package/src/lib/fieldReference/style.scss +0 -273
  64. package/src/lib/fieldReference/test.spec.ts +0 -44
  65. package/src/lib/fieldReference/view.html +0 -163
  66. package/src/lib/fieldRichtext/index.ts +0 -98
  67. package/src/lib/fieldRichtext/quill.scss +0 -6
  68. package/src/lib/fieldRichtext/style.scss +0 -87
  69. package/src/lib/fieldRichtext/test.spec.ts +0 -43
  70. package/src/lib/fieldRichtext/view.html +0 -17
  71. package/src/lib/fieldSelect/index.ts +0 -597
  72. package/src/lib/fieldSelect/style.scss +0 -165
  73. package/src/lib/fieldSelect/test.spec.ts +0 -44
  74. package/src/lib/fieldSelect/view.html +0 -128
  75. package/src/lib/fieldText/index.ts +0 -86
  76. package/src/lib/fieldText/style.scss +0 -24
  77. package/src/lib/fieldText/test.spec.ts +0 -43
  78. package/src/lib/fieldText/view.html +0 -23
  79. package/src/lib/fieldUnknown/index.ts +0 -15
  80. package/src/lib/fieldUnknown/test.spec.ts +0 -34
  81. package/src/lib/fieldUnknown/view.html +0 -9
  82. package/src/lib/index.ts +0 -127
  83. package/src/lib/layout/index.ts +0 -255
  84. package/src/lib/layout/style.scss +0 -67
  85. package/src/lib/layout/view.html +0 -45
  86. package/src/lib/metaField/index.ts +0 -133
  87. package/src/lib/metaField/test.spec.ts +0 -32
  88. package/src/lib/refDialog/index.ts +0 -157
  89. package/src/lib/refDialog/style.scss +0 -154
  90. package/src/lib/refDialog/view.html +0 -24
  91. package/src/lib/resource/index.ts +0 -559
  92. package/src/lib/resource/style.scss +0 -132
  93. package/src/lib/resource/view.html +0 -70
  94. package/src/lib/resourceCard/index.ts +0 -44
  95. package/src/lib/resourceCard/style.scss +0 -7
  96. package/src/lib/resourceCard/view.html +0 -14
  97. package/src/lib/services/metaContext/index.ts +0 -61
  98. package/src/lib/services/metaMsg/index.ts +0 -84
  99. package/src/lib/services/metaReference/index.ts +0 -98
  100. package/src/lib/services/metaResource/index.ts +0 -163
  101. package/src/lib/services/metaResource/metaHttpClient.ts +0 -76
  102. package/src/lib/services/metaResource/metaResource.spec.ts +0 -24
  103. package/src/lib/services/metaTracker/index.ts +0 -38
  104. package/src/lib/services/resourceDrafts/index.ts +0 -81
  105. package/src/lib/services/resourceDrafts/resourceDrafts.spec.ts +0 -24
  106. package/src/lib/styles.scss +0 -13
  107. package/src/public-api.ts +0 -5
  108. package/src/test.ts +0 -17
  109. package/tsconfig.lib.json +0 -25
  110. package/tsconfig.lib.prod.json +0 -9
  111. package/tsconfig.spec.json +0 -17
@@ -1,871 +0,0 @@
1
- import { Component, OnInit, ViewContainerRef } from '@angular/core';
2
- import { FieldAbstract } from '../fieldAbstract';
3
- import { ControlContainer, NgForm } from '@angular/forms';
4
- import { MetaReferenceService } from '../services/metaReference';
5
- import { Subject } from 'rxjs';
6
- import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
7
- import { MetaResourceService, IMetaResourceConfig } from '../services/metaResource';
8
- import { MetaRefDialog } from '../refDialog';
9
- import { MetaMsgService } from '../services/metaMsg';
10
- import { MetaContextService } from '../services/metaContext';
11
- import { IMetaTrackerEvent, MetaTrackerService } from '../services/metaTracker';
12
-
13
- @Component({
14
- templateUrl: './view.html',
15
- styleUrls: ['./style.scss'],
16
- viewProviders: [{ provide: ControlContainer, useExisting: NgForm }],
17
- standalone: false
18
- })
19
- export class FieldReference extends FieldAbstract implements OnInit {
20
- input: any;
21
- dropdown: HTMLElement;
22
- dropdownScrollContainer: HTMLElement;
23
- searching: boolean;
24
- searchResourceType: any = {};
25
- searchText: string;
26
- searchResults: Array<any>;
27
- searchError: any;
28
- activeSuggestionIndex: number;
29
- searchResourceTypesScope: string;
30
- searchTextChanged: Subject<string> = new Subject<string>();
31
- isCreatable = false;
32
- value: any;
33
- isPolymorphic: boolean;
34
- isSearchable: boolean;
35
- multiple: boolean;
36
- vr: MetaResourceService;
37
- externalLink: string;
38
- dropdownVisible = false;
39
- searchResourceTypeMeta: any = {
40
- type: 'select',
41
- name: 'resourceType',
42
- label: 'Type',
43
- options: [], // { label: '-- All types --' }],
44
- standalone: true
45
- };
46
- filteredSuggestions: Array<any> = [];
47
- placeHolderLabel: string;
48
- asyncSuggestions: Array<any>;
49
- smartSuggestions: Array<any> = [];
50
-
51
- constructor(
52
- private referenceService: MetaReferenceService,
53
- private metaResource: MetaResourceService,
54
- private metaMsgService: MetaMsgService,
55
- private metaContext: MetaContextService,
56
- private metaTracker: MetaTrackerService,
57
- private viewContainerRef: ViewContainerRef
58
- ) {
59
- super();
60
- }
61
-
62
- get disabled() {
63
- const superDisabled = this.logicalDisabled || this.validations.disabled || this.meta.disabled === true
64
- || (this.meta.updatable === false && this.isPersistedParent);
65
- this.searchResourceTypeMeta.disabled = superDisabled;
66
- return superDisabled;
67
- }
68
-
69
- get showTypes() {
70
- return (typeof (this.meta.showTypes) !== 'undefined') ? this.meta.showTypes : true;
71
- }
72
-
73
- get suggestions() {
74
- return this.smartSuggestions.concat(
75
- !this.searchResourceType.resourceType ?
76
- // eslint-disable-next-line max-len
77
- (this.asyncSuggestions || this.meta.suggestions || []) : (this.asyncSuggestions || this.meta.suggestions || []).filter((s) => s.type === this.searchResourceType.resourceType)
78
- );
79
- }
80
-
81
- get hasAppendButton() {
82
- if (!this.multiple && this.model) {
83
- if (this.isPolymorphic) {
84
- for (const ref of this.metaReference) {
85
- if ((ref.name || ref.resourceType) === (this.model.type || this.model.resourceType)) {
86
- return ref.updatable || (ref.creatable && ref.updatable !== false);
87
- }
88
- }
89
- } else {
90
- return this.metaReference.updatable || (this.metaReference.creatable && this.metaReference.updatable !== false); // VGIS-6911
91
- }
92
- } else if (this.metaReference instanceof Array) {
93
- // setTimeout(() => {
94
- // this.searchResourceTypesScope = this.metaReference.map(rt => rt.name).join(',');
95
- // }, 0);
96
- for (const rt of this.metaReference) {
97
- if (rt.hidden !== false && rt.creatable) {
98
- return true;
99
- }
100
- }
101
- } else {
102
- return this.metaReference.creatable;
103
- }
104
- }
105
-
106
- get resourceService() {
107
- if (!this.metaResourceService) {
108
- const metaResourceConfig: IMetaResourceConfig = {
109
- integrationCode: this.integrationCode,
110
- resourceType: this.resourceType,
111
- delegate: this.delegate
112
- };
113
- this.metaResourceService = this.metaResource.new(metaResourceConfig);
114
- }
115
- return this.metaResourceService;
116
- }
117
-
118
- get metaReference() {
119
- return this.meta.reference || {};
120
- }
121
-
122
- ngOnInit() {
123
- this.multiple = (this.meta.type === 'multireference') || this.meta.multiple;
124
- this.searchResourceTypeMeta.label = this.meta.label;
125
- if (!this.meta.valueType) {
126
- // this.meta.valueType = 'object';
127
- Object.defineProperty(this.meta, 'valueType', {
128
- value: 'object'
129
- });
130
- }
131
- if (this.metaReference instanceof Array) {
132
- this.isPolymorphic = true;
133
- this.isSearchable = true;
134
- this.searchResourceTypesScope = this.metaReference.filter(rt => rt.hidden !== true).map(rt => rt.name).join(',');
135
- for (const rt of this.metaReference) {
136
- if (rt.creatable) {
137
- this.isCreatable = true;
138
- if (typeof (rt.searchable) !== 'undefined' && !rt.searchable) {
139
- this.isSearchable = false;
140
- }
141
- }
142
- }
143
- this.metaReference.forEach((r) => {
144
- if (!r.hidden) {
145
- this.searchResourceTypeMeta.options.push({ id: r.name, label: r.label || r.name });
146
- }
147
- });
148
- } else {
149
- this.isSearchable = typeof (this.metaReference.searchable) === 'undefined' || this.metaReference.searchable;
150
- this.searchResourceType = this.metaReference;
151
- this.searchResourceTypesScope = this.metaReference.name || this.metaReference.resourceType;
152
- this.isCreatable = this.metaReference.creatable;
153
- }
154
- this.buildPlaceholderLabel();
155
- this.searchTextChanged.pipe(debounceTime(300), distinctUntilChanged()).subscribe((value: string) => {
156
- this.searchText = value;
157
- this.search();
158
- });
159
- const origValue = this.parent[this.meta.name];
160
-
161
- // this.suggestions = this.meta.suggestions; // TODO filter by default type
162
- // console.log('this.suggestions', this.suggestions);
163
-
164
- Object.defineProperty(this.parent, this.meta.name, {
165
- set: (value) => {
166
- if (value === '') {
167
- value = null;
168
- }
169
- if (this.multiple) {
170
- if (value && value instanceof Array) {
171
- for (const v of value) {
172
- if (!this.model) {
173
- this.model = [];
174
- }
175
- if (typeof (v) === 'string') {
176
- this.model.push({
177
- id: v,
178
- label: v,
179
- type: this.metaReference.name
180
- });
181
- }
182
- }
183
- } else {
184
- value = null; // protect when value from server is not array
185
- }
186
- } else {
187
- if (typeof (value) === 'string') {
188
- value = {
189
- id: value,
190
- label: value, // could be found with extra call
191
- type: this.metaReference.name
192
- };
193
- }
194
- this.searchText = value ?
195
- ((!value.label || value.label === ' ') ? `N/A (${value.type}#${value.id})` : value.label || value) :
196
- '';
197
- // if (this.isPolymorphic && this.model) { //TODO show or not?
198
- // this.searchResourceType = this.metaReference.find((rt)=> {
199
- // return rt.name === this.model.type;
200
- // });
201
- // }
202
- }
203
- this.model = value;
204
- if (!this.multiple) {
205
- this.value = this.modelToValue(value, this.meta.valueType || 'object');
206
- this.buildExternalLink();
207
- } else {
208
- this.value = !this.model ? this.model : this.model.map((m) => this.modelToValue(m, this.meta.valueType || 'object'));
209
- }
210
- this.meta.$optional = this.isOptional;
211
- },
212
- get: () => this.value,
213
- enumerable: this.sendToServer,
214
- configurable: true
215
- });
216
- if (origValue) {
217
- this.parent[this.meta.name] = origValue;
218
- }
219
- if (!this.model && this.default) {
220
- if (this.multiple) {
221
- this.parent[this.meta.name] = [];
222
- if (this.default.length) {
223
- for (const dv of this.default) {
224
- if ((dv.id || dv.value) && dv.type) {
225
- const item: any = {
226
- id: dv.id || dv.value,
227
- label: dv.label || dv.id || dv.value,
228
- type: dv.type
229
- };
230
- if (dv.externalLink) {
231
- item.externalLink = dv.externalLink;
232
- }
233
- this.parent[this.meta.name].push(item);
234
- }
235
- }
236
- }
237
- if (!this.parent[this.meta.name].length) {
238
- this.clear();
239
- }
240
- } else {
241
- if (this.default.id && this.default.label && this.default.type) {
242
- setTimeout(() => {
243
- if (!this.model) {
244
- const item: any = {
245
- id: this.default.id || this.default.value,
246
- label: this.default.label || this.default.id || this.default.value,
247
- type: this.default.type,
248
- smart: true
249
- };
250
- if (this.default.externalLink) {
251
- item.externalLink = this.default.externalLink;
252
- }
253
- this.parent[this.meta.name] = item;
254
- }
255
- }, 0);
256
- } else {
257
- console.warn('!!!default value is not valid format', this.meta);
258
- }
259
- }
260
- }
261
-
262
- if (typeof (this.meta.disabled) !== 'undefined') {
263
- if (typeof (this.meta.disabled) === 'object') {
264
- for (const p of Object.keys(this.meta.disabled)) {
265
- const props = p.split('.');
266
- if (typeof (this.parent[props[0]]) !== 'undefined') {
267
- let val = this.parent;
268
- for (const prop of props) {
269
- val = val[prop];
270
- if (!val) {
271
- break;
272
- }
273
- }
274
- if (val === this.meta.disabled[p]) {
275
- this.logicalDisabled = true;
276
- this.clear();
277
- }
278
- }
279
- this.parentChangeSubject.subscribe((value) => {
280
- if (value && value.hasOwnProperty(props[0])) {
281
- let val = this.parent;
282
- for (const prop of props) {
283
- val = val[prop];
284
- if (!val) {
285
- break;
286
- }
287
- }
288
- if (val === this.meta.disabled[p]) {
289
- this.logicalDisabled = true;
290
- this.clear();
291
- } else {
292
- delete this.logicalDisabled;
293
- }
294
- }
295
- });
296
- }
297
- }
298
- }
299
-
300
- if (this.meta.auto && this.meta.auto.search) {
301
- const searchParams = this.meta.auto.search.params;
302
- if (searchParams) {
303
- for (const par of Object.keys(searchParams)) {
304
- const props = searchParams[par].split('.');
305
- const field = props[0];
306
- const prop = props[1];
307
- let parValue = this.parent[field];
308
- if (parValue) {
309
- if (prop) {
310
- parValue = parValue[prop];
311
- }
312
- if (parValue) {
313
- const params = {};
314
- params[par] = parValue;
315
- this.searchAutoSuggestions(params);
316
- }
317
- }
318
- this.parentChangeSubject.subscribe((value) => {
319
- if (value && value.hasOwnProperty(field)) {
320
- if (value[field]) {
321
- if (prop) {
322
- value[field] = value[field][prop];
323
- }
324
- const params = {};
325
- params[par] = value[field];
326
- this.searchAutoSuggestions(params);
327
- }
328
- }
329
- });
330
- }
331
- }
332
- }
333
- }
334
-
335
- clearSearchResourceType() {
336
- this.searchResourceType = {};
337
- this.onSearchResourceTypeChanged();
338
- }
339
-
340
- onSearchResourceTypeChanged(resourceType?) {
341
- if (!resourceType || !resourceType.id) {
342
- this.searchResourceType.resourceType = null;
343
- this.searchResourceTypesScope = (this.metaReference || []).filter(rt => rt.hidden !== true).map(rt => rt.name).join(',');
344
- } else {
345
- this.searchResourceType.resourceType = resourceType.id;
346
- this.searchResourceTypesScope = resourceType.id;
347
- }
348
- this.buildPlaceholderLabel();
349
- this.focus();
350
- if (!this.model && !this.searchText) { // filter suggestions by type
351
- this.filteredSuggestions = !resourceType ? (this.meta.suggestions || []) : (this.meta.suggestions || []).filter(
352
- (s) => s.type === resourceType.id
353
- );
354
- } else { // regular search (return scoped results)
355
- if (!this.model) {
356
- this.search();
357
- } else if (this.searchResults && resourceType) {
358
- this.searchResults = this.searchResults.filter((s) => s.type === resourceType.id);
359
- }
360
- }
361
- delete this.searchError;
362
- }
363
-
364
- onSearchTextChanged(value: string) {
365
- this.searchTextChanged.next(value);
366
- }
367
-
368
- search() {
369
- this.searching = true;
370
- // this.activeSuggestionIndex;
371
- if (!this.searchText || this.searchText.length < 2) {
372
- this.searching = false;
373
- delete this.searchResults;
374
- return;
375
- }
376
- const showSearchResults = (results) => {
377
- this.searching = false;
378
- delete this.searchError;
379
- delete this.activeSuggestionIndex;
380
- if (!results || !(results instanceof Array)) {
381
- results = [];
382
- }
383
- if (this.meta.acceptNew && this.meta.acceptNew.type && this.meta.acceptNew.pattern) {
384
- const regex = new RegExp(this.meta.acceptNew.pattern);
385
- if (regex.test(this.searchText)) {
386
- results.unshift({ id: null, label: this.searchText, type: this.meta.acceptNew.type });
387
- }
388
- }
389
- this.searchResults = results.map((r) => { // eslint-disable-line arrow-body-style
390
- return { id: r.id, label: r.label, type: r.type || r.resourceType || this.searchResourceType.name, externalLink: r.externalLink };
391
- });
392
- if (!/Vlt-dropdown--expanded/.test(this.dropdown.className)) {
393
- this.showDropdown();
394
- }
395
- };
396
-
397
- if (this.meta.search) {
398
- const searchParams = this.meta.search.params || {};
399
- let searchUrl = `/fields/${this.meta.name}/search`;
400
- if (this.meta.search.url) {
401
- searchUrl = this.meta.search.url.replace(/\${\s*([\w.]+)\s*}/g, (match, key) => {
402
- if (searchParams.hasOwnProperty(key)) {
403
- const props = searchParams[key].split('.');
404
- const field = props[0];
405
- const prop = props[1];
406
- delete searchParams[key]; // if it is URL param, remove it as query param
407
- let parValue = this.parent[field];
408
- if (parValue) {
409
- if (prop) {
410
- parValue = parValue[prop];
411
- }
412
- if (parValue) {
413
- return parValue;
414
- }
415
- }
416
- }
417
- return 'undefined';
418
- });
419
- }
420
- for (const p of Object.keys(searchParams)) {
421
- searchUrl += `${searchUrl.indexOf('?') === -1 ? '?' : '&'}${encodeURIComponent(p)}=${encodeURIComponent(searchParams[p])}`;
422
- }
423
- searchUrl += `${searchUrl.indexOf('?') === -1 ? '?' : '&'}q=${encodeURIComponent(this.searchText)}`;
424
- this.searching = true;
425
- this.resourceService.getByPath(searchUrl).subscribe((results) => {
426
- showSearchResults(results);
427
- }, (error) => {
428
- delete this.searching;
429
- this.searchResults = [];
430
- this.searchError = error.error ? error.error.message || error.error : error.message || error;
431
- if (!/Vlt-dropdown--expanded/.test(this.dropdown.className)) {
432
- this.showDropdown();
433
- }
434
- });
435
- } else {
436
- if (!this.vr) {
437
- this.vr = this.metaResource.new({
438
- integrationCode: this.integrationCode,
439
- resourceType: null,
440
- delegate: this.delegate
441
- });
442
- }
443
- this.vr.searchIntegration(
444
- this.searchText,
445
- this.searchResourceType.name || this.searchResourceTypesScope
446
- ).subscribe((results: Array<any>) => {
447
- showSearchResults(results);
448
- }, (error) => {
449
- this.searching = false;
450
- this.searchResults = [];
451
- this.searchError = error.error ? error.error.message || error.error : error.message || error;
452
- if (!/Vlt-dropdown--expanded/.test(this.dropdown.className)) {
453
- this.showDropdown();
454
- }
455
- });
456
- }
457
- }
458
-
459
- onActivated(ev) {
460
- // ev.preventDefault();
461
- // ev.stopPropagation();
462
- this.input = ev.srcElement;
463
- if (!this.dropdown) {
464
- // this.dropdown = ev.srcElement.parentNode.parentNode;
465
- this.dropdown = this.elementRef.nativeElement.querySelector('.dropdown-wrapper');
466
- }
467
- this.showDropdown();
468
- }
469
-
470
- onBlur(ev) {
471
- let internalControl = false;
472
- if (ev.relatedTarget) {
473
- if (!this.elementRef.nativeElement.contains(ev.relatedTarget)) {
474
- this.dismissDropdown();
475
- } else {
476
- internalControl = true;
477
- }
478
- }
479
- if (this.keyListenerActive && !internalControl) {
480
- this.input.removeEventListener('keydown', this.keydown);
481
- setTimeout(() => {
482
- if (!this.keyListenerActive) {
483
- document.removeEventListener('click', this.clickout);
484
- }
485
- }, 400);
486
- delete this.keyListenerActive;
487
- }
488
- }
489
-
490
- removeSelection(ev?) {
491
- if (ev) {
492
- ev.preventDefault();
493
- ev.stopPropagation();
494
- }
495
- if (this.model && !this.suggestions.find((s) => (s.id === this.model.id && s.type === this.model.type))) {
496
- this.smartSuggestions.push({
497
- id: this.model.id,
498
- label: this.model.label,
499
- type: this.model.type,
500
- smart: true
501
- });
502
- }
503
- this.metaTracker.emit(this.buildTrackEvent('REMOVE'));
504
- this.clear();
505
- }
506
-
507
- onSuggestionSelect(ev, suggestion) {
508
- if (!suggestion) {
509
- return;
510
- }
511
- ev.preventDefault();
512
- ev.stopPropagation();
513
- this.focus();
514
- this.metaTracker.emit(this.buildTrackEvent('SELECT'));
515
- if (this.multiple) {
516
- if (!this.model) {
517
- this.model = [];
518
- }
519
- let existingEntry;
520
- for (const entry of this.model) {
521
- if (suggestion.id && (entry.id === suggestion.id)) {
522
- existingEntry = entry;
523
- break;
524
- } else if (suggestion.label === entry.label) { // create new (google emails)
525
- existingEntry = entry;
526
- break;
527
- }
528
- }
529
- if (!existingEntry) {
530
- this.model.push(suggestion);
531
- }
532
- this.onModelChange(this.model);
533
- delete this.searchText;
534
- this.searchTextChanged.next(this.searchText);
535
- } else {
536
- this.model = suggestion;
537
- this.externalLink = suggestion.externalLink;
538
- this.onModelChange(suggestion);
539
- this.searchText = suggestion.label;
540
- this.activeSuggestionIndex = (this.searchResults || this.suggestions).indexOf(suggestion);
541
- }
542
- this.dismissDropdown();
543
- // if (this.isPolymorphic) {
544
- // this.searchResourceType = this.metaReference.find((rt)=> {
545
- // return rt.name === suggestion.type;
546
- // });
547
- // }
548
- }
549
-
550
- showDropdown() {
551
- if (this.disabled) {
552
- return;
553
- }
554
- this.dropdownVisible = true;
555
- this.dropdown.classList.add('Vlt-dropdown--expanded');
556
- if (!this.keyListenerActive) {
557
- this.input.addEventListener('keydown', this.keydown);
558
- setTimeout(() => {
559
- document.addEventListener('click', this.clickout);
560
- }, 200);
561
- this.keyListenerActive = true;
562
- }
563
- if (typeof (this.activeSuggestionIndex) === 'undefined') {
564
- if (this.model && (this.searchResults || this.suggestions)) {
565
- for (let suggestionIndex = 0; suggestionIndex < (this.searchResults || this.suggestions).length; suggestionIndex++) {
566
- const item = (this.searchResults || this.suggestions)[suggestionIndex];
567
- if (this.model.id === item.id && this.model.type === item.type) {
568
- this.activeSuggestionIndex = suggestionIndex;
569
- break;
570
- }
571
- }
572
- }
573
- }
574
- this.ensureDropdownIsVisible();
575
- }
576
-
577
- dismissDropdown(event?) {
578
- this.dropdownVisible = false;
579
- if (event) {
580
- this.focus();
581
- }
582
- if (this.dropdown) {
583
- this.dropdown.classList.remove('Vlt-dropdown--expanded');
584
- }
585
- }
586
-
587
- clear() {
588
- this.prevModel = this.model;
589
- delete this.searchText;
590
- delete this.searchResults;
591
- delete this.model;
592
- delete this.activeSuggestionIndex;
593
- this.onModelChange(this.model);
594
- this.onSearchTextChanged(this.searchText);
595
- this.focus();
596
- }
597
-
598
- revert() {
599
- this.model = this.prevModel;
600
- delete this.prevModel;
601
- this.onModelChange(this.model);
602
- this.focus();
603
- }
604
-
605
- remove(ev, item) {
606
- ev.preventDefault();
607
- ev.stopPropagation();
608
- const optionIndex = this.model.indexOf(item);
609
- if (optionIndex !== -1) {
610
- this.model.splice(optionIndex, 1);
611
- if (!this.model.length) {
612
- delete this.model;
613
- delete this.value;
614
- }
615
- this.onModelChange(this.model);
616
- }
617
- }
618
-
619
- openResource(model?) {
620
- this.keyListenerActive = true; // suppress dropdown in this case
621
- setTimeout(() => {
622
- this.dismissDropdown();
623
- });
624
- const refDialogComponent = this.viewContainerRef.createComponent(MetaRefDialog);
625
- this.metaTracker.emit(this.buildTrackEvent(model ? 'EDIT' : 'NEW'));
626
- let theme = this.elementRef.nativeElement.dataset.theme;
627
- if (!theme || theme === 'inherit') {
628
- let parentComponent = this.elementRef.nativeElement.closest('vgip-meta-layout');
629
- if (parentComponent) {
630
- theme = parentComponent.dataset.theme;
631
- }
632
- if (!theme || theme === 'inherit') {
633
- parentComponent = this.elementRef.nativeElement.closest('vgip-meta-resource');
634
- if (parentComponent) {
635
- theme = parentComponent.dataset.theme;
636
- }
637
- }
638
- }
639
- this.referenceService.openDialog(
640
- refDialogComponent, this.metaResource, this.integrationCode,
641
- (this.metaReference instanceof Array) ? this.metaReference.filter(rt => rt.hidden !== true) : this.metaReference,
642
- model, null, this.searchResourceType.resourceType, theme, this.overlayContainer
643
- ).subscribe((result: any) => {
644
- if (result) {
645
- this.parent[this.meta.name] = result;
646
- this.onChange.emit(result);
647
- const existingSuggestion = (this.meta.suggestions || []).find((s) => (s.id === result.id && s.type === result.type));
648
- if (existingSuggestion) {
649
- existingSuggestion.label = result.label;
650
- } else {
651
- if (!this.meta.suggestions) {
652
- this.meta.suggestions = [];
653
- }
654
- this.meta.suggestions.unshift(result);
655
- }
656
- this.metaTracker.emit(this.buildTrackEvent(model ? 'UPDATE' : 'CREATE', result.type || result.resourceType));
657
- } else {
658
- this.metaTracker.emit(this.buildTrackEvent(model ? 'CANCEL_EDIT' : 'CANCEL_UPDATE'));
659
- }
660
- });
661
- }
662
-
663
- private ensureDropdownIsVisible() {
664
- setTimeout(() => {
665
- const holder = this.dropdown.closest('.Vlt-card__content, .Vlt-modal__content');
666
- if (holder) {
667
- const el = this.elementRef.nativeElement.querySelector('.Vlt-dropdown__panel');
668
- const elRect = el.getBoundingClientRect();
669
- const holderRect = holder.getBoundingClientRect();
670
- if (holderRect.top + holderRect.height < elRect.top + elRect.height) {
671
- el.scrollIntoView({ block: 'end' });
672
- }
673
- }
674
- }, 400);
675
- }
676
-
677
- private ensureDropdownOptionIsVisible() {
678
- if (!this.dropdownScrollContainer) {
679
- this.dropdownScrollContainer = this.dropdown.querySelector('.Vlt-dropdown__scroll');
680
- }
681
- if (this.dropdownScrollContainer && typeof (this.activeSuggestionIndex) === 'number') {
682
- const scrollTop = 44 * this.activeSuggestionIndex;
683
- const scrollBottom = 44 * (this.activeSuggestionIndex - 7);
684
- if (scrollTop < this.dropdownScrollContainer.scrollTop) {
685
- this.dropdownScrollContainer.scrollTop = scrollTop;
686
- } else if (scrollBottom > this.dropdownScrollContainer.scrollTop) {
687
- this.dropdownScrollContainer.scrollTop = scrollBottom;
688
- }
689
- }
690
- }
691
-
692
- private clickout = (event) => {
693
- const internalControl = this.elementRef.nativeElement.contains(event.target);
694
- if (internalControl && ['Vlt-dropdown__link', 'Vlt-dropdown__block'].indexOf(event.target.className) !== -1) {
695
- this.focus();
696
- } else if (!internalControl && event.target !== this.input && event.target.className !== 'Vlt-dropdown__title') {
697
- this.dismissDropdown();
698
- } else {
699
- if (!internalControl && internalControl.tagName !== 'INPUT') {
700
- this.focus();
701
- }
702
- }
703
- };
704
-
705
- private buildTrackEvent(action: string, value?: string) {
706
- const e: IMetaTrackerEvent = {
707
- integration: this.integrationCode,
708
- resource: this.model ? (this.model.type || this.model.resourceType) : this.searchResourceType.resourceType,
709
- field: this.meta.name,
710
- action
711
- };
712
- if (this.meta.$isContactable) {
713
- e.isContactable = true;
714
- }
715
- if (typeof (value) !== 'undefined') {
716
- e.value = value;
717
- }
718
- return e;
719
- }
720
-
721
- private buildPlaceholderLabel() {
722
- this.placeHolderLabel = this.meta.label;
723
- if (this.multiple && !this.isPolymorphic) {
724
- this.placeHolderLabel = '+Add ';
725
- } else {
726
- this.placeHolderLabel = (this.isSearchable && (this.multiple || !this.isPolymorphic)) ? 'Search ' : '';
727
- }
728
- this.placeHolderLabel += this.searchResourceType.resourceType ? this.searchResourceType.resourceType : this.searchResourceTypesScope;
729
- }
730
-
731
- private keydown = (event) => {
732
- switch (event.key) {
733
- case 'ArrowDown': {
734
- this.showDropdown();
735
- if (typeof (this.activeSuggestionIndex) === 'undefined') {
736
- this.activeSuggestionIndex = 0;
737
- } else {
738
- this.activeSuggestionIndex++;
739
- if (this.activeSuggestionIndex >= (this.searchResults || this.suggestions).length) {
740
- this.activeSuggestionIndex = 0;
741
- }
742
- }
743
- this.ensureDropdownOptionIsVisible();
744
- event.preventDefault();
745
- event.stopPropagation();
746
- break;
747
- }
748
- case 'ArrowUp': {
749
- this.showDropdown();
750
- if (typeof (this.activeSuggestionIndex) === 'undefined') {
751
- this.activeSuggestionIndex = (this.searchResults || this.suggestions).length - 1;
752
- } else {
753
- this.activeSuggestionIndex--;
754
- if (this.activeSuggestionIndex < 0) {
755
- this.activeSuggestionIndex = (this.searchResults || this.suggestions).length - 1;
756
- }
757
- }
758
- this.ensureDropdownOptionIsVisible();
759
- event.preventDefault();
760
- event.stopPropagation();
761
- break;
762
- }
763
- case 'Space':
764
- case 'Enter': {
765
- if (typeof (this.activeSuggestionIndex) !== 'undefined') {
766
- event.preventDefault();
767
- event.stopPropagation();
768
- this.onSuggestionSelect(event, (this.searchResults || this.suggestions)[this.activeSuggestionIndex]);
769
- delete this.activeSuggestionIndex;
770
- }
771
- break;
772
- }
773
- case 'Escape': {
774
- event.preventDefault();
775
- event.stopPropagation();
776
- this.dismissDropdown();
777
- break;
778
- }
779
- case 'Backspace': {
780
- if (!this.multiple && this.model) { // HPBR-8229
781
- event.preventDefault();
782
- event.stopPropagation();
783
- this.removeSelection();
784
- }
785
- break;
786
- }
787
- }
788
- };
789
-
790
- private buildExternalLink() {
791
- if (this.model) {
792
- if (this.model.externalLink) {
793
- this.externalLink = this.model.externalLink;
794
- } else if (this.metaContext.profiles[this.integrationCode.toUpperCase()]) {
795
- delete this.externalLink;
796
- this.metaMsgService.sendMessage(
797
- this.integrationCode.toUpperCase(),
798
- {
799
- action: 'buildExternalLink',
800
- integrationCode: this.integrationCode,
801
- ref: this.model,
802
- profile: this.metaContext.profiles[this.integrationCode.toUpperCase()]
803
- },
804
- (response) => {
805
- if (!response.error) {
806
- this.externalLink = response.externalLink;
807
- } else {
808
- console.warn('No external link support for', this.integrationCode, this.model.resourceType || this.model.type);
809
- }
810
- }
811
- );
812
- }
813
- } else {
814
- delete this.externalLink;
815
- }
816
- }
817
-
818
- private searchAutoSuggestions(params?) {
819
- let searchUrl = `/suggestions/${this.meta.name}/search`;
820
- if (this.meta.auto && this.meta.auto.search) {
821
- if (this.meta.auto.search.url) {
822
- searchUrl = this.meta.auto.search.url.replace(/\${\s*([\w.]+)\s*}/g, (match, key) => {
823
- if (params.hasOwnProperty(key)) {
824
- const val = params[key];
825
- delete params[key];
826
- return val;
827
- }
828
- return '';
829
- });
830
- }
831
- for (const p of Object.keys(params)) {
832
- searchUrl += `${searchUrl.indexOf('?') === -1 ? '?' : '&'}${encodeURIComponent(p)}=${encodeURIComponent(params[p])}`;
833
- }
834
- this.searching = true;
835
- this.resourceService.getByPath(searchUrl).subscribe((result) => {
836
- delete this.searching;
837
- if (result) {
838
- let suggestions;
839
- suggestions = result;
840
- if (this.meta.auto.search.extract) {
841
- suggestions = result[this.meta.auto.search.extract];
842
- }
843
- if (suggestions instanceof Array !== true) {
844
- suggestions = [suggestions];
845
- }
846
- const asyncSuggestions = [];
847
- suggestions.forEach((s) => {
848
- if (s && s.id && s.type) { // TOOD check the type is acceptable
849
- asyncSuggestions.push({
850
- id: s.id,
851
- label: s.label || `${s.type}#${s.id}`,
852
- type: s.type
853
- });
854
- }
855
- });
856
- if (asyncSuggestions.length) {
857
- if (asyncSuggestions.length === 1) {
858
- this.parent[this.meta.name] = asyncSuggestions[0];
859
- } else {
860
- delete this.asyncSuggestions;
861
- }
862
- }
863
- this.asyncSuggestions = asyncSuggestions;
864
- }
865
- }, () => {
866
- delete this.searching;
867
- });
868
- }
869
- }
870
-
871
- }