@vgip/meta-ui 2.1.1 → 2.1.3

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 (118) hide show
  1. package/.eslintrc.json +57 -0
  2. package/karma.conf.js +35 -0
  3. package/ng-package.json +10 -0
  4. package/package.json +4 -16
  5. package/src/lib/common/fieldNormalizer/boolean.ts +11 -0
  6. package/src/lib/common/fieldNormalizer/datetime.ts +8 -0
  7. package/src/lib/common/fieldNormalizer/index.ts +171 -0
  8. package/src/lib/common/fieldNormalizer/number.ts +13 -0
  9. package/src/lib/common/fieldNormalizer/options.ts +48 -0
  10. package/src/lib/common/fieldNormalizer/radio.ts +29 -0
  11. package/src/lib/common/fieldNormalizer/reference.ts +32 -0
  12. package/src/lib/common/fieldNormalizer/richtext.ts +15 -0
  13. package/src/lib/common/fieldNormalizer/string.ts +23 -0
  14. package/src/lib/common/fieldNormalizer/text.ts +17 -0
  15. package/src/lib/common/fieldNormalizer/uniqueNameFilter.ts +21 -0
  16. package/src/lib/common/metaAutofocus.directive.ts +31 -0
  17. package/src/lib/common/metaContext.resolver.ts +25 -0
  18. package/src/lib/common/metaIcons.pipe.spec.ts +15 -0
  19. package/src/lib/common/metaIcons.pipe.ts +29 -0
  20. package/src/lib/common/metaModel.pipe.ts +19 -0
  21. package/src/lib/common/metaNormalizer.ts +366 -0
  22. package/src/lib/common/metaStripHtml.pipe.ts +18 -0
  23. package/src/lib/common/utils/colorThemes.ts +86 -0
  24. package/src/lib/common/utils/indexedDbStore/index.ts +244 -0
  25. package/src/lib/common/utils/indexedDbStore/indexedDbStore.spec.ts +149 -0
  26. package/src/lib/common/utils/relativeTimeBuilder.ts +49 -0
  27. package/src/lib/common/utils/resourceCardLabel.ts +25 -0
  28. package/src/lib/common/utils/smartProp.spec.ts +24 -0
  29. package/src/lib/common/utils/smartProp.ts +28 -0
  30. package/src/lib/common/utils/templateBuilder.ts +99 -0
  31. package/src/lib/field.scss +207 -0
  32. package/src/lib/fieldAbstract.ts +327 -0
  33. package/src/lib/fieldBoolean/index.ts +55 -0
  34. package/src/lib/fieldBoolean/style.scss +22 -0
  35. package/src/lib/fieldBoolean/test.spec.ts +43 -0
  36. package/src/lib/fieldBoolean/view.html +30 -0
  37. package/src/lib/fieldComposite/index.ts +86 -0
  38. package/src/lib/fieldComposite/style.scss +6 -0
  39. package/src/lib/fieldComposite/test.spec.ts +43 -0
  40. package/src/lib/fieldComposite/view.html +9 -0
  41. package/src/lib/fieldDatetime/index.ts +359 -0
  42. package/src/lib/fieldDatetime/style.scss +81 -0
  43. package/src/lib/fieldDatetime/test.spec.ts +43 -0
  44. package/src/lib/fieldDatetime/view.html +26 -0
  45. package/src/lib/fieldHidden/index.ts +15 -0
  46. package/src/lib/fieldHidden/view.html +0 -0
  47. package/src/lib/fieldInput/index.ts +477 -0
  48. package/src/lib/fieldInput/style.scss +128 -0
  49. package/src/lib/fieldInput/test.spec.ts +43 -0
  50. package/src/lib/fieldInput/view.html +81 -0
  51. package/src/lib/fieldList/index.ts +73 -0
  52. package/src/lib/fieldList/style.scss +26 -0
  53. package/src/lib/fieldList/test.spec.ts +43 -0
  54. package/src/lib/fieldList/view.html +25 -0
  55. package/src/lib/fieldRadio/index.ts +93 -0
  56. package/src/lib/fieldRadio/style.scss +32 -0
  57. package/src/lib/fieldRadio/test.spec.ts +43 -0
  58. package/src/lib/fieldRadio/view.html +24 -0
  59. package/src/lib/fieldReference/index.ts +871 -0
  60. package/src/lib/fieldReference/style.scss +273 -0
  61. package/src/lib/fieldReference/test.spec.ts +44 -0
  62. package/src/lib/fieldReference/view.html +163 -0
  63. package/src/lib/fieldRichtext/index.ts +98 -0
  64. package/src/lib/fieldRichtext/quill.scss +6 -0
  65. package/src/lib/fieldRichtext/style.scss +87 -0
  66. package/src/lib/fieldRichtext/test.spec.ts +43 -0
  67. package/src/lib/fieldRichtext/view.html +17 -0
  68. package/src/lib/fieldSelect/index.ts +597 -0
  69. package/src/lib/fieldSelect/style.scss +165 -0
  70. package/src/lib/fieldSelect/test.spec.ts +44 -0
  71. package/src/lib/fieldSelect/view.html +128 -0
  72. package/src/lib/fieldText/index.ts +86 -0
  73. package/src/lib/fieldText/style.scss +24 -0
  74. package/src/lib/fieldText/test.spec.ts +43 -0
  75. package/src/lib/fieldText/view.html +23 -0
  76. package/src/lib/fieldUnknown/index.ts +15 -0
  77. package/src/lib/fieldUnknown/test.spec.ts +34 -0
  78. package/src/lib/fieldUnknown/view.html +9 -0
  79. package/src/lib/index.ts +127 -0
  80. package/src/lib/layout/index.ts +255 -0
  81. package/src/lib/layout/style.scss +67 -0
  82. package/src/lib/layout/view.html +45 -0
  83. package/src/lib/metaField/index.ts +133 -0
  84. package/src/lib/metaField/test.spec.ts +32 -0
  85. package/src/lib/refDialog/index.ts +157 -0
  86. package/src/lib/refDialog/style.scss +154 -0
  87. package/src/lib/refDialog/view.html +24 -0
  88. package/src/lib/resource/index.ts +559 -0
  89. package/src/lib/resource/style.scss +132 -0
  90. package/src/lib/resource/view.html +70 -0
  91. package/src/lib/resourceCard/index.ts +44 -0
  92. package/src/lib/resourceCard/style.scss +7 -0
  93. package/src/lib/resourceCard/view.html +14 -0
  94. package/src/lib/services/metaContext/index.ts +61 -0
  95. package/src/lib/services/metaMsg/index.ts +84 -0
  96. package/src/lib/services/metaReference/index.ts +98 -0
  97. package/src/lib/services/metaResource/index.ts +163 -0
  98. package/src/lib/services/metaResource/metaHttpClient.ts +76 -0
  99. package/src/lib/services/metaResource/metaResource.spec.ts +24 -0
  100. package/src/lib/services/metaTracker/index.ts +38 -0
  101. package/src/lib/services/resourceDrafts/index.ts +81 -0
  102. package/src/lib/services/resourceDrafts/resourceDrafts.spec.ts +24 -0
  103. package/src/lib/styles.scss +13 -0
  104. package/src/public-api.ts +5 -0
  105. package/src/test.ts +17 -0
  106. package/tsconfig.lib.json +25 -0
  107. package/tsconfig.lib.prod.json +9 -0
  108. package/tsconfig.spec.json +17 -0
  109. package/vendor/volta3/scss/components/_accordions.scss +5 -1
  110. package/vendor/volta3/scss/components/_callouts.scss +6 -2
  111. package/vendor/volta3/scss/components/_card.scss +1 -1
  112. package/vendor/volta3/scss/components/_form-elements.scss +1 -1
  113. package/vendor/volta3/scss/components/_modals.scss +1 -1
  114. package/vendor/volta3/scss/components/_tables.scss +1 -1
  115. package/vendor/volta3/scss/lib/_variables.scss +1 -1
  116. package/fesm2022/vgip-meta-ui.mjs +0 -6076
  117. package/fesm2022/vgip-meta-ui.mjs.map +0 -1
  118. package/index.d.ts +0 -709
@@ -0,0 +1,477 @@
1
+ /*
2
+ * @Author: Alexander.Vangelov@vonage.com
3
+ * @Date: 2019-09-19 17:35:09
4
+ * @Last Modified by: Alexander.Vangelov@vonage.com
5
+ * @Last Modified time: 2020-05-12 17:45:46
6
+ */
7
+
8
+ import { Component, OnInit } from '@angular/core';
9
+ import { ControlContainer, NgForm } from '@angular/forms';
10
+
11
+ import { FieldAbstract } from '../fieldAbstract';
12
+ // import { IMetaFieldInut } from '../definitions/fields/IMetaFieldInput';
13
+ import { templateBuilder } from '../common/utils/templateBuilder';
14
+ import { relativeTimeBuilder } from '../common/utils/relativeTimeBuilder';
15
+ import { MetaContextService } from '../services/metaContext';
16
+
17
+ // import { MetaValidations } from '../common/decorators/metaValidations.decorator';
18
+
19
+ @Component({
20
+ templateUrl: './view.html',
21
+ styleUrls: ['./style.scss'],
22
+ viewProviders: [{ provide: ControlContainer, useExisting: NgForm }],
23
+ standalone: false
24
+ })
25
+ export class FieldInput extends FieldAbstract implements OnInit {
26
+ input: any;
27
+ dropdown: any;
28
+ activeSuggestionIndex: number;
29
+ value: any;
30
+ multiple: boolean;
31
+ addText;
32
+ showClear: boolean;
33
+ asyncSuggestions: Array<any>;
34
+ isPhoneNumber: boolean;
35
+ logicalSubtype: string;
36
+
37
+ constructor( private metaContext: MetaContextService ) {
38
+ super();
39
+ }
40
+
41
+ get suggestions() {
42
+ return this.asyncSuggestions || this.meta.suggestions || [];
43
+ }
44
+
45
+ ngOnInit() {
46
+ this.multiple = (this.meta.type === 'multistring') || this.meta.multiple;
47
+ // console.log('FieldInput init', this.meta.name);
48
+ this.validationAttributes = ['pattern', 'required', 'minlength', 'maxlength', 'min', 'max', 'step'];
49
+ if (this.meta.picklist) { // just for test! all metadata should be transformed to v3 protocol
50
+ this.meta.suggestions = (this.meta.picklist || []).map((s) => s.label);
51
+ }
52
+ if (this.meta.type === 'number') {
53
+ this.logicalSubtype = 'number';
54
+ }
55
+ if (['date', 'time', 'datetime'].indexOf(this.meta.type) !== -1) {
56
+ this.logicalSubtype = this.meta.type;
57
+ if (this.meta.type === 'datetime') {
58
+ this.logicalSubtype = 'datetime-local';
59
+ }
60
+ delete this.multiple; // no multiple support for timestamps
61
+ }
62
+ this.showClear = !this.multiple && [
63
+ '', 'string', 'url', 'email', 'password', 'tel', 'date', 'datetime-local', 'time'
64
+ ].indexOf(this.meta.subtype || '') !== -1;
65
+ const origValue = this.parent[this.meta.name];
66
+ Object.defineProperty(this.parent, this.meta.name, {
67
+ set: (value) => {
68
+ if (this.multiple) {
69
+ if (typeof(value) !== 'undefined') {
70
+ const values = (value instanceof Array) ? value : [value];
71
+ this.model = [];
72
+ for (let v of values) {
73
+ if (!this.model) {
74
+ this.model = [];
75
+ }
76
+ if (typeof (v) === 'object' && v !== null) {
77
+ v = v.id || v.value;
78
+ }
79
+ this.model.push(v);
80
+ }
81
+ this.value = this.model;
82
+ }
83
+ } else {
84
+ if (typeof(value) !== 'undefined'
85
+ && !(value === null && ((typeof(this.meta.type) === 'undefined') || ['string', 'number'].indexOf(this.meta.type) !== -1))
86
+ ) {
87
+ if (this.meta.type === 'number' && typeof(value) === 'string') {
88
+ value = parseInt(value, 10);
89
+ } else if (typeof (value) === 'object' && value !== null) {
90
+ value = value.id || value.value;
91
+ }
92
+ if (['datetime', 'date', 'datetime-local'].indexOf(this.meta.subtype || this.meta.type) !== -1 && value) {
93
+ try {
94
+ let date: Date;
95
+ if ((typeof (value) === 'number')) {
96
+ date = new Date(parseInt(value as any, 10));
97
+ if ('date' === (this.meta.type || this.meta.subtype)) {
98
+ date = new Date(date.getTime() + (date.getTimezoneOffset() * 60000));
99
+ }
100
+ } else {
101
+ if ('date' === (this.meta.subtype || this.meta.type)) {
102
+ date = new Date(Date.parse(value));
103
+ } else {
104
+ date = new Date(Date.parse(`${value}Z`) + (new Date().getTimezoneOffset() * 60000));
105
+ }
106
+ }
107
+ if (typeof (value) === 'number') {
108
+ switch (this.meta.subtype || this.meta.type) {
109
+ case 'datetime-local':
110
+ case 'datetime': {
111
+ this.model = `${date.getFullYear()}-${('00' + (date.getMonth() + 1)).slice(-2)}-${('00' + date.getDate()).slice(-2)}`;
112
+ this.model += `T${('00' + date.getHours()).slice(-2)}:${('00' + date.getMinutes()).slice(-2)}`;
113
+ break;
114
+ }
115
+ case 'date': {
116
+ this.model = date.toISOString().split('T')[0];
117
+ break;
118
+ }
119
+ }
120
+ }
121
+ if (this.meta.valueType === 'string') {
122
+ if ((this.meta.subtype || this.meta.type) === 'date') {
123
+ this.value = date.toISOString().split('T')[0];
124
+ } else {
125
+ this.value = date.toISOString();
126
+ }
127
+ } else {
128
+ if ((this.meta.subtype || this.meta.type) === 'date') {
129
+ date.setFullYear(date.getUTCFullYear());
130
+ date.setMonth(date.getUTCMonth());
131
+ date.setDate(date.getUTCDate());
132
+ date.setMinutes(0);
133
+ date.setHours(0);
134
+ date.setSeconds(0);
135
+ date.setMilliseconds(0);
136
+ this.value = new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).getTime();
137
+ } else {
138
+ this.value = date.getTime();
139
+ }
140
+ }
141
+ } catch (e) {
142
+ console.error('Date parse error', e.message, `"${value}"`, `(${typeof (value)})`);
143
+ }
144
+ } else if ('time' === (this.meta.subtype || this.meta.type)) {
145
+ try {
146
+ let date: Date;
147
+ if (typeof (value) === 'number') {
148
+ date = new Date(parseInt(value as any, 10));
149
+ if (value < 86400000) {
150
+ date = new Date(date.getTime() + (date.getTimezoneOffset() * 60000));
151
+ }
152
+ } else {
153
+ date = new Date(
154
+ Date.parse(new Date().toISOString().replace(/T.*Z/, `T${value}Z`)) + (new Date().getTimezoneOffset() * 60000)
155
+ );
156
+ }
157
+ this.model = date.toTimeString().split(' ')[0];
158
+ date.setFullYear(1970);
159
+ date.setMonth(0);
160
+ date.setDate(1);
161
+ date.setMilliseconds(0);
162
+ this.value = new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).getTime();
163
+ } catch (e) {
164
+ console.error('Date parse error', e.message, `"${value}"`, `(${typeof (value)})`);
165
+ }
166
+ } else {
167
+ if (!value && (typeof(this.prevModel) === 'string') && this.isPersistedParent) {
168
+ value = '';
169
+ }
170
+ this.model = value;
171
+ this.value = value;
172
+ }
173
+ } else {
174
+ delete this.model;
175
+ delete this.value;
176
+ }
177
+ }
178
+ this.meta.$optional = this.isOptional;
179
+ },
180
+ get: () => this.value,
181
+ enumerable: this.sendToServer,
182
+ configurable: true
183
+ });
184
+ if (typeof(origValue) !== 'undefined') {
185
+ this.parent[this.meta.name] = origValue;
186
+ }
187
+ if (!this.isPersistedParent && typeof(this.meta.auto?.template) === 'string') {
188
+ this.metaContext.onContextChange.subscribe((context) => {
189
+ const autoValue = templateBuilder({ context }, this.meta.auto.template);
190
+ if (this.model === this.lastAutoValue && autoValue) {
191
+ this.lastAutoValue = autoValue;
192
+ this.parent[this.meta.name] = autoValue;
193
+ }
194
+ });
195
+ }
196
+ const d = this.meta.default || this.meta.defaultValue;
197
+ if (d && typeof(this.model) === 'undefined') {
198
+ if (this.multiple) {
199
+ this.parent[this.meta.name] = [];
200
+ if (d.length) {
201
+ for (const dv of this.default) { // TODO ???
202
+ const defaultValueItem = (typeof (dv) === 'string' || dv === null) ? dv : (dv.id || dv.value);
203
+ if (defaultValueItem || defaultValueItem === 0) {
204
+ this.parent[this.meta.name].push(defaultValueItem);
205
+ }
206
+ }
207
+ }
208
+ } else {
209
+ const defaultValue = (typeof (d) === 'string') ? d : (d.id || d.value);
210
+ if (defaultValue || defaultValue === 0) {
211
+ if (/^(date|time)/.test(this.meta.subtype) && typeof(defaultValue) === 'string') {
212
+ this.parent[this.meta.name] = relativeTimeBuilder(this.meta.subtype, defaultValue, this.validations.step);
213
+ } else {
214
+ if (this.meta.type === 'string' && defaultValue) {
215
+ this.parent[this.meta.name] = templateBuilder(this.metaContext, defaultValue);
216
+ } else {
217
+ this.parent[this.meta.name] = defaultValue;
218
+ }
219
+ }
220
+ }
221
+ }
222
+ this.lastAutoValue = this.model;
223
+ }
224
+ if (this.preview && this.metaContext.onClick2Dial && origValue) {
225
+ this.isPhoneNumber = /^(?:00|\+)?(([01]|44|61|48|33( )?\d|27|30|31|34|371|380|39|41|420|52|40|90|91)(\s)?)?[-./]?\(?\d?\d{1,3}\)?[-\s./]?\d?[-\s./]?\d{1,4}\)?[-\s./]?\d{1,4}[-./]?\d{1,4}(\s\d\d($|,))?(,[,\d]+#)?$/.test(origValue);
226
+ }
227
+ }
228
+
229
+ onActivated(ev) {
230
+ this.input = ev.srcElement;
231
+ if (!this.dropdown) {
232
+ this.dropdown = ev.srcElement.parentNode.parentNode;
233
+ }
234
+ this.showDropdown();
235
+ }
236
+
237
+ clear(ev?) {
238
+ delete this.model;
239
+ delete this.activeSuggestionIndex;
240
+ delete this.asyncSuggestions;
241
+ this.onModelChange(this.model);
242
+ if (ev) {
243
+ ev.preventDefault();
244
+ ev.stopPropagation();
245
+ this.focus();
246
+ return false;
247
+ }
248
+ }
249
+
250
+ onBlur(ev) {
251
+ let internalControl = false;
252
+ if (ev.relatedTarget) {
253
+ if (!this.elementRef.nativeElement.contains(ev.relatedTarget)) {
254
+ this.dismissDropdown();
255
+ } else {
256
+ internalControl = true;
257
+ }
258
+ }
259
+ if (this.keyListenerActive && !internalControl) {
260
+ this.input.removeEventListener('keydown', this.keydown);
261
+ setTimeout(() => {
262
+ if (!this.keyListenerActive) {
263
+ document.removeEventListener('click', this.clickout);
264
+ }
265
+ }, 400);
266
+ delete this.keyListenerActive;
267
+ }
268
+ }
269
+
270
+ onAdd(ev) {
271
+ console.log('onAdd', this.addText);
272
+ if (this.addText) {
273
+ if ((this.model || []).indexOf(this.addText) === -1) {
274
+ this.onSuggestionSelect(ev, this.addText);
275
+ if (!this.meta.suggestions) {
276
+ this.meta.suggestions = [];
277
+ }
278
+ this.meta.suggestions.unshift(this.addText);
279
+ } else {
280
+ ev.preventDefault();
281
+ ev.stopPropagation();
282
+ this.focus();
283
+ }
284
+ delete this.addText;
285
+ }
286
+ }
287
+
288
+ remove(ev, item) {
289
+ ev.preventDefault();
290
+ ev.stopPropagation();
291
+ const optionIndex = this.model.indexOf(item);
292
+ if (optionIndex !== -1) {
293
+ this.model.splice(optionIndex, 1);
294
+ if (!this.model.length) {
295
+ delete this.model;
296
+ delete this.value;
297
+ }
298
+ this.onModelChange(this.model);
299
+ }
300
+ }
301
+
302
+ onSuggestionSelect(ev, suggestion) {
303
+ if (!suggestion) {
304
+ return;
305
+ }
306
+ ev.preventDefault();
307
+ ev.stopPropagation();
308
+ this.focus();
309
+ let suggestionValue = suggestion.id || suggestion.value || suggestion;
310
+ if (typeof(suggestionValue) === 'string') {
311
+ if (/^(date|time)/.test(this.meta.subtype)) {
312
+ suggestionValue = relativeTimeBuilder(this.meta.subtype, suggestionValue, this.validations.step);
313
+ } else if (this.meta.type === 'string') {
314
+ suggestionValue = templateBuilder(this.metaContext, suggestionValue);
315
+ } else {
316
+ suggestionValue = suggestion;
317
+ }
318
+ }
319
+ if (this.multiple) {
320
+ if (!this.model) {
321
+ this.model = [];
322
+ }
323
+ let existingItemIndex = this.model.indexOf(suggestionValue);
324
+ if (existingItemIndex === -1) {
325
+ this.model.push(suggestionValue);
326
+ } else {
327
+ this.model.splice(existingItemIndex, 1);
328
+ existingItemIndex = undefined;
329
+ }
330
+ this.onModelChange(this.model);
331
+ } else {
332
+ this.dismissDropdown();
333
+ this.model = suggestionValue;
334
+ this.onModelChange(suggestionValue);
335
+ this.activeSuggestionIndex = this.suggestions.indexOf(suggestion);
336
+ }
337
+ }
338
+
339
+ textToSpeech() { }
340
+
341
+ dismissDropdown(event?) {
342
+ if (event) {
343
+ this.focus();
344
+ }
345
+ if (this.dropdown) {
346
+ this.dropdown.classList.remove('Vlt-dropdown--expanded');
347
+ }
348
+ }
349
+
350
+ click2dial(ev) {
351
+ ev.preventDefault();
352
+ ev.stopPropagation();
353
+ this.metaContext.onClick2Dial(this.model, this.elementRef.nativeElement.closest('vgip-meta-layout[data-vrn]')?.dataset?.vrn);
354
+ return false;
355
+ }
356
+
357
+ private ensureDropdownIsVisible() {
358
+ setTimeout(() => {
359
+ const holder = this.dropdown.closest('.Vlt-card__content, .Vlt-modal__content');
360
+ if (holder) {
361
+ const el = this.elementRef.nativeElement.querySelector('.Vlt-dropdown__panel');
362
+ if (el) {
363
+ const elRect = el.getBoundingClientRect();
364
+ const holderRect = holder.getBoundingClientRect();
365
+ if (holderRect.top + holderRect.height < elRect.top + elRect.height) {
366
+ el.scrollIntoView({ block: 'end' });
367
+ }
368
+ }
369
+ }
370
+ }, 400);
371
+ }
372
+
373
+ private showDropdown() {
374
+ if (this.meta.suggestions?.length) {
375
+ this.dropdown.classList.add('Vlt-dropdown--expanded');
376
+ this.ensureDropdownIsVisible();
377
+ }
378
+ if (!this.keyListenerActive) {
379
+ this.input.addEventListener('keydown', this.keydown);
380
+ setTimeout(() => {
381
+ document.addEventListener('click', this.clickout);
382
+ }, 200);
383
+ this.keyListenerActive = true;
384
+ }
385
+ if (typeof(this.activeSuggestionIndex) === 'undefined') {
386
+ if (this.model && this.suggestions.length) {
387
+ for (let suggestionIndex = 0; suggestionIndex < this.suggestions.length; suggestionIndex++) {
388
+ if (this.model === this.suggestions[suggestionIndex]) {
389
+ this.activeSuggestionIndex = suggestionIndex;
390
+ return;
391
+ }
392
+ }
393
+ delete this.activeSuggestionIndex;
394
+ }
395
+ }
396
+ }
397
+
398
+ private clickout = (event) => {
399
+ if (event.target.className === 'Vlt-dropdown__link' && this.elementRef.nativeElement.contains(event.target)) {
400
+ this.focus();
401
+ // this.dismissDropdown();
402
+ // this.parent[this.meta.name] = event.target.textContent;
403
+
404
+ } else if (event.target !== this.input && event.target.className !== 'Vlt-dropdown__title') {
405
+ this.dismissDropdown();
406
+ } else {
407
+ this.focus();
408
+ }
409
+ };
410
+
411
+ private keydown = (event) => {
412
+ switch (event.key) {
413
+ case 'ArrowDown': {
414
+ if (['datetime', 'time', 'date', 'datetime-local'].indexOf(this.meta.subtype || this.meta.type) !== -1) {
415
+ break;
416
+ }
417
+ this.showDropdown();
418
+ event.preventDefault();
419
+ if (typeof (this.activeSuggestionIndex) === 'undefined') {
420
+ this.activeSuggestionIndex = 0;
421
+ } else {
422
+ this.activeSuggestionIndex++;
423
+ if (this.activeSuggestionIndex >= this.suggestions.length) {
424
+ this.activeSuggestionIndex = 0;
425
+ }
426
+ }
427
+ break;
428
+ }
429
+ case 'ArrowUp': {
430
+ if (['datetime', 'time', 'date', 'datetime-local'].indexOf(this.meta.subtype || this.meta.type) !== -1) {
431
+ break;
432
+ }
433
+ this.showDropdown();
434
+ event.preventDefault();
435
+ if (typeof (this.activeSuggestionIndex) === 'undefined') {
436
+ this.activeSuggestionIndex = this.suggestions.length - 1;
437
+ } else {
438
+ this.activeSuggestionIndex--;
439
+ if (this.activeSuggestionIndex < 0) {
440
+ this.activeSuggestionIndex = this.suggestions.length - 1;
441
+ }
442
+ }
443
+ break;
444
+ }
445
+ case 'Space':
446
+ case 'Enter': {
447
+ if (typeof (this.activeSuggestionIndex) !== 'undefined') {
448
+ event.preventDefault();
449
+ event.stopPropagation();
450
+ this.onSuggestionSelect(event, this.suggestions[this.activeSuggestionIndex]);
451
+ delete this.activeSuggestionIndex;
452
+ }
453
+ break;
454
+ }
455
+ case 'Escape': {
456
+ event.preventDefault();
457
+ event.stopPropagation();
458
+ this.dismissDropdown();
459
+ break;
460
+ }
461
+ default: {
462
+ setTimeout(() => {
463
+ if (!this.model) {
464
+ delete this.activeSuggestionIndex;
465
+ delete this.asyncSuggestions;
466
+ } else if (typeof(this.model) === 'string') {
467
+ this.asyncSuggestions = (this.meta.suggestions || []).filter((s) => {
468
+ const suggestionText = (s.id || s.value || s || '').toLowerCase();
469
+ return suggestionText.indexOf(this.model.toLowerCase()) !== -1;
470
+ });
471
+ }
472
+ });
473
+ }
474
+ }
475
+ };
476
+
477
+ }
@@ -0,0 +1,128 @@
1
+ .Vlt-form__element--big {
2
+ .Vlt-input input {
3
+ padding-right: 40px;
4
+ text-overflow: ellipsis;
5
+ @media screen and (-webkit-min-device-pixel-ratio: 0) { // Safari iOS fix
6
+ line-height: 20px;
7
+ }
8
+ &:disabled {
9
+ cursor: not-allowed;
10
+ }
11
+ }
12
+ &:hover, &.active {
13
+ .items-container, .main, input {
14
+ border-color: var(--vgip-meta-input-active-border-color);
15
+ }
16
+ }
17
+ &.multiple {
18
+ .Vlt-composite.Vlt-dropdown {
19
+ margin-top: 3px;
20
+ }
21
+ &:hover:not(.Vlt-form__element--error), &.active:not(.Vlt-form__element--error) {
22
+ .items-container, .main, input {
23
+ border-color: var(--vgip-meta-input-active-border-color);
24
+ }
25
+ }
26
+ .items-container {
27
+ background-color: var(--vgip-meta-input-bg-color);
28
+ border: 1px solid var(--vgip-meta-input-border-color);
29
+ border-bottom: 0;
30
+ border-top-left-radius: 6px;
31
+ border-top-right-radius: 6px;
32
+ &.creatable {
33
+ margin-right: 62px;
34
+ }
35
+ .badges-container {
36
+ overflow: auto;
37
+ max-height: 140px;
38
+ padding: 6px 4px 0 6px;
39
+ .Vlt-badge {
40
+ margin-bottom: 3px;
41
+ margin-left: 0;
42
+ margin-right: 3px;
43
+ overflow: hidden;
44
+ max-width: 100%;
45
+ }
46
+ }
47
+ }
48
+ &:not(.has-value) .items-container {
49
+ border: 0;
50
+ }
51
+ &.has-value {
52
+ .main, input {
53
+ border-top: 0;
54
+ border-top-left-radius: 0;
55
+ border-top-right-radius: 0;
56
+ box-shadow: none;
57
+ }
58
+ }
59
+ }
60
+ &.Vlt-form__element--error {
61
+ .items-container, .main, input {
62
+ border-color: #f25a6b;
63
+ background: var(--vgip-meta-input-bg-color);
64
+ }
65
+ }
66
+ }
67
+ // .Vlt-dropdown__link:focus {
68
+ // background: rgba(44, 45, 48, 0.1);
69
+ // }
70
+ label.Vlt-truncate {
71
+ padding-right: 42px;
72
+ }
73
+
74
+ .Vlt-dropdown__panel {
75
+ width: 100%;
76
+ .Vlt-dropdown__link--selected {
77
+ background: rgba(44, 45, 48, 0.05);
78
+ }
79
+ // .Vlt-dropdown__link > div {
80
+ // overflow: hidden;
81
+ // white-space: nowrap;
82
+ // text-overflow: ellipsis;
83
+ // }
84
+ label {
85
+ margin-top: 0;
86
+ padding: 12px 20px;
87
+ top: 0;
88
+ left: 0;
89
+ pointer-events: initial;
90
+ position: initial;
91
+ color: initial;
92
+ font-size: inherit;
93
+ transition: none;
94
+ cursor: pointer;
95
+ // .Vlt-checkbox__icon {
96
+ // background: initial;
97
+ // // border: 2px solid #e7ebee;
98
+ // }
99
+ input {
100
+ height: 0;
101
+ }
102
+ }
103
+ }
104
+
105
+ .Vlt-composite__append.right-actions {
106
+ position: absolute;
107
+ top: 5px;
108
+ right: 10px;
109
+ cursor: pointer;
110
+ .Vlt-composite__append--icon {
111
+ width: 36px;
112
+ outline: none;
113
+ position: initial;
114
+ display: inline-block;
115
+ svg {
116
+ height: 14px;
117
+ width: 14px;
118
+ }
119
+ }
120
+ .Vlt-composite__append--icon:hover svg, .Vlt-composite__append--icon:focus svg {
121
+ fill: var(--vgip-meta-input-accent-color);
122
+ }
123
+ }
124
+
125
+ .vgip-disable .Vlt-composite__append{
126
+ cursor: not-allowed;
127
+ pointer-events: none;
128
+ }
@@ -0,0 +1,43 @@
1
+ /*
2
+ * @Author: Alexander.Vangelov@vonage.com
3
+ * @Date: 2019-09-19 17:35:19
4
+ * @Last Modified by: Alexander.Vangelov@vonage.com
5
+ * @Last Modified time: 2019-11-13 15:54:23
6
+ */
7
+
8
+ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
9
+ import { NgForm } from '@angular/forms';
10
+
11
+ import { MetaModule } from '..';
12
+
13
+ import { FieldInput } from '.';
14
+
15
+ describe('FieldInput', () => {
16
+ let component: FieldInput;
17
+ let fixture: ComponentFixture<FieldInput>;
18
+
19
+ beforeEach(waitForAsync(() => {
20
+ TestBed.configureTestingModule({
21
+ declarations: [],
22
+ imports: [
23
+ MetaModule
24
+ ],
25
+ providers: [
26
+ { provide: NgForm, useValue: new NgForm([], []) }
27
+ ]
28
+ })
29
+ .compileComponents();
30
+ }));
31
+
32
+ beforeEach(() => {
33
+ fixture = TestBed.createComponent(FieldInput);
34
+ component = fixture.componentInstance;
35
+ component.parent = {};
36
+ component.meta = { name: 'f1' };
37
+ fixture.detectChanges();
38
+ });
39
+
40
+ it('should create', () => {
41
+ expect(component).toBeTruthy();
42
+ });
43
+ });