@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,207 @@
1
+
2
+ :host {
3
+ ::ng-deep label.wrapper {
4
+ padding: 0;
5
+ pointer-events: initial;
6
+ position: initial;
7
+ top: initial;
8
+ transition: none;
9
+ }
10
+
11
+ ::ng-deep .hidden-mobile {
12
+ @media only screen and (max-width: 575px) {
13
+ display: none;
14
+ }
15
+ }
16
+ ::ng-deep .hidden-desktop {
17
+ @media only screen and (min-width: 576px) {
18
+ display: none;
19
+ }
20
+ }
21
+
22
+ ::ng-deep .Vlt-form__element {
23
+ > .Vlt-label, > label > .Vlt-label {
24
+ margin-top: -6px;
25
+ }
26
+ }
27
+
28
+ ::ng-deep .Vlt-form__element {
29
+ .Vlt-form__element__hint {
30
+ color: var(--vgip-meta-input-hint-color);
31
+ }
32
+ .Vlt-input input, .Vlt-select select, .Vlt-textarea textarea {
33
+ color: var(--vgip-meta-input-color);
34
+ @media (hover:none) { // fix zooming on iOS
35
+ font-size: 16px;
36
+ }
37
+ &::placeholder {
38
+ color: var(--vgip-meta-input-placeholder-color);
39
+ }
40
+ }
41
+ label {
42
+ color: var(--vgip-meta-input-label-color);
43
+ }
44
+ &:not(.Vlt-form__element--error) {
45
+ .Vlt-form-error-style,
46
+ .Vlt-input input,
47
+ .Vlt-input input.ng-untouched:invalid,
48
+ .Vlt-select select.ng-untouched:invalid,
49
+ .Vlt-textarea textarea,
50
+ .Vlt-textarea textarea.ng-untouched:invalid,
51
+ .Vlt-custom-select__input:invalid,
52
+ .Vlt-radio input.ng-untouched:invalid + .Vlt-radio__icon,
53
+ .Vlt-radio input.ng-untouched:invalid + .Vlt-checkbox__icon,
54
+ .Vlt-checkbox input.ng-untouched:invalid + .Vlt-radio__icon,
55
+ .Vlt-checkbox input.ng-untouched:invalid + .Vlt-checkbox__icon {
56
+ background: var(--vgip-meta-input-bg-color);
57
+ border-color: var(--vgip-meta-input-border-color);
58
+ &:disabled {
59
+ background: var(--vgip-meta-input-disabled-bg-color);
60
+ border-color: var(--vgip-meta-input-disabled-border-color);
61
+ }
62
+ &:hover, &:focus, .active {
63
+ border-color: var(--vgip-meta-input-active-border-color);
64
+ }
65
+ }
66
+ }
67
+ &.Vlt-form__element--error {
68
+ .Vlt-input input:focus,
69
+ .Vlt-select select:focus,
70
+ .Vlt-textarea textarea:focus,
71
+ .Vlt-custom-select__input:focus {
72
+ border-color: #f25a6b;
73
+ }
74
+ }
75
+ }
76
+
77
+ ::ng-deep .Vlt-dropdown__link {
78
+ padding: 12px;
79
+ svg {
80
+ margin-left: 0;
81
+ }
82
+ small {
83
+ line-height: inherit;
84
+ }
85
+ &.Vlt-dropdown__link--selected:after {
86
+ width: 20px;
87
+ top: 14px;
88
+ background: var(--vgip-meta-dropdown-check-icon) no-repeat right center;
89
+ background-size: contain;
90
+ }
91
+ }
92
+ ::ng-deep .Vlt-dropdown__block {
93
+ padding: 2px 16px;
94
+ }
95
+ ::ng-deep .meta-field-reference .Vlt-dropdown__link.has-type.Vlt-dropdown__link--selected:after {
96
+ position: initial;
97
+ }
98
+ ::ng-deep .Vlt-dropdown__panel__content {
99
+ background: var(--vgip-meta-dropdown-bg-color);
100
+ box-shadow: var(--vgip-meta-dropdown-shadow);
101
+ .Vlt-dropdown__link, .Vlt-dropdown__block {
102
+ color: var(--vgip-meta-input-color);
103
+ }
104
+
105
+ .Vlt-dropdown__scroll::-webkit-scrollbar {
106
+ width: 8px;
107
+ }
108
+
109
+ .Vlt-dropdown__scroll::-webkit-scrollbar-thumb {
110
+ background-color: var(--vgip-meta-scrollbar-color);
111
+ border: 2px solid transparent;
112
+ border-radius: 6px;
113
+ background-clip: content-box;
114
+ }
115
+ &.suggestions {
116
+ background: var(--vgip-meta-suggestions-bg-color)
117
+ }
118
+ }
119
+
120
+ ::ng-deep .Vlt-dropdown__panel {
121
+ z-index: 999;
122
+ }
123
+ ::ng-deep .Vlt-dropdown__panel__content--scroll-area {
124
+ // box-shadow: 0 1px 20px rgba(44, 45, 48, 0.3);
125
+ padding: 0;
126
+ }
127
+ ::ng-deep .Vlt-composite__append--icon {
128
+ bottom: 0;
129
+ // background-color: #ffffff;
130
+ height: initial;
131
+ }
132
+
133
+ ::ng-deep .search-progress {
134
+ display: block;
135
+ position: relative;
136
+ width: 100%;
137
+ height: 3px;
138
+ margin-top: -3px;
139
+ padding-top: 0 !important;
140
+ margin-bottom: 0 !important;
141
+ .container {
142
+ display:block;
143
+ position: relative;
144
+ overflow: hidden;
145
+
146
+ width:100%;
147
+ height: 3px;
148
+
149
+ transform: translate(0, 0) scale(1, 1);
150
+
151
+ .bar {
152
+ position: absolute;
153
+
154
+ left: 0;
155
+ top: 0;
156
+ bottom: 0;
157
+
158
+ width: 100%;
159
+ height: 3px;
160
+
161
+ border-radius: 50%;
162
+ transition: all 0.3s linear;
163
+ animation: query 0.9s infinite cubic-bezier(0.3, 0.6, 0.6, 1.000);
164
+ }
165
+
166
+ @keyframes query {
167
+ 0% {
168
+ opacity: 1;
169
+ transform: translateX(35%) scale(.3, 1);
170
+ }
171
+ 100% {
172
+ opacity: 0;
173
+ transform: translateX(-50%) scale(0, 1);
174
+ }
175
+ }
176
+ }
177
+ }
178
+ }
179
+
180
+ ::ng-deep vgip-meta-field.shown vgip-meta-field {
181
+ display: initial;
182
+ }
183
+ ::ng-deep vgip-meta-field .vgip-meta-field-preview {
184
+ display: flex;
185
+ flex-direction: row;
186
+ padding-bottom: 5px;
187
+ padding-top: 5px;
188
+ margin-left: 10px;
189
+ border-bottom: 1px solid #e7ebee;
190
+ .vgip-meta-field-label {
191
+ flex: 1 1 100%;
192
+ max-width: 20%;
193
+ max-height: 100%;
194
+ box-sizing: border-box;
195
+ overflow: hidden;
196
+ white-space: nowrap;
197
+ text-overflow: ellipsis;
198
+ margin-right: 2px;
199
+ }
200
+ .vgip-meta-field-value {
201
+ min-width: 0;
202
+ width: 0;
203
+ box-sizing: border-box;
204
+ flex: 1;
205
+ font-weight: bold;
206
+ }
207
+ }
@@ -0,0 +1,327 @@
1
+ /*
2
+ * @Author: Alexander.Vangelov@vonage.com
3
+ * @Date: 2019-09-19 17:34:44
4
+ * @Last Modified by: Alexander.Vangelov@vonage.com
5
+ * @Last Modified time: 2020-04-18 21:18:08
6
+ */
7
+
8
+ import { ElementRef, AfterViewInit, EventEmitter, Directive } from '@angular/core';
9
+ // import { ControlValueAccessor } from '@angular/forms';
10
+ import { BehaviorSubject } from 'rxjs';
11
+ import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
12
+ import { metaDark, metaLight } from './common/utils/colorThemes';
13
+ import { extractValueBySmartProp, extractBooleanValueBySmartProp } from '../lib/common/utils/smartProp';
14
+
15
+ // export interface IMetaField<T extends FieldAbstract> {
16
+ // meta: any;
17
+ // model: any;
18
+ // }
19
+
20
+ @Directive()
21
+ // eslint-disable-next-line @angular-eslint/directive-class-suffix
22
+ export abstract class FieldAbstract implements AfterViewInit { // implements ControlValueAccessor {
23
+ model: any;
24
+ meta: any;
25
+ index: number;
26
+ scope = '';
27
+ parent: any;
28
+ integrationCode: string;
29
+ integrationIcon: string;
30
+ resourceType: string;
31
+ elementRef: ElementRef;
32
+ modelInput: HTMLInputElement;
33
+ modelControl: HTMLInputElement;
34
+ mainInput: HTMLInputElement;
35
+ keyListenerActive: boolean;
36
+ onChange: EventEmitter<any>;
37
+ onLeave: EventEmitter<any>;
38
+ validationAttributes = [];
39
+ preview: boolean;
40
+ prevModel: any;
41
+ changeEvent = document.createEvent('MouseEvents');
42
+ metaResourceService: any;
43
+ logicalDisabled = false;
44
+ theme: string;
45
+ flags: any = {};
46
+ overlayContainer: HTMLElement;
47
+ lastAutoValue: any;
48
+ delegate: any;
49
+
50
+ get parentChangeSubject() {
51
+ if (!Object.getOwnPropertyDescriptor(this.parent, '$changeSubject')) {
52
+ Object.defineProperty(this.parent, '$changeSubject', {
53
+ value: new BehaviorSubject({}).pipe(debounceTime(300), distinctUntilChanged()),
54
+ writable: false,
55
+ enumerable: false
56
+ });
57
+ }
58
+ return this.parent.$changeSubject;
59
+ }
60
+
61
+ get isPersistedParent() {
62
+ // eslint-disable-next-line no-underscore-dangle
63
+ return this.parent && this.parent._vgis && (this.parent._vgis.externalId || this.parent._vgis.id );
64
+ }
65
+
66
+ get validations() {
67
+ return !this.meta.$invisible ? (this.meta.validations || {}) : {};
68
+ }
69
+
70
+ get name() {
71
+ return (typeof (this.index) === 'undefined') ? `${this.scope}${this.meta.name}` : `${this.scope}${this.meta.name}[${this.index}]`;
72
+ }
73
+
74
+ get default() {
75
+ return this.meta.default || this.meta.defaultValue;
76
+ }
77
+
78
+ get disabled() {
79
+ // TODO conditions
80
+ return this.logicalDisabled || this.validations.disabled || this.meta.disabled === true || this.flags.disabled
81
+ || (this.flags.updatable === false && this.isPersistedParent);
82
+ }
83
+
84
+ get readonly() {
85
+ // TODO conditions
86
+ return !!(this.validations.readonly || this.meta.readonly || (this.flags.updatable === false));
87
+ }
88
+
89
+ get sendToServer() {
90
+ return this.isPersistedParent ? (this.flags.updatable !== false) : (this.flags.creatable !== false);
91
+ }
92
+
93
+ get uiInput() {
94
+ if (!this.mainInput) {
95
+ this.mainInput = this.elementRef.nativeElement.querySelector('.main:not([type="hidden"]):not(.standalone)');
96
+ }
97
+ return this.mainInput;
98
+ }
99
+
100
+ get isOptional() {
101
+ const baseOptional = this.preview || (!this.meta.unset && !this.validations.required && !this.meta.visible);
102
+ switch (this.meta.type) {
103
+ case 'composite': {
104
+ if (baseOptional) {
105
+ return !this.meta.fields.find((f) => !f.$optional);
106
+ }
107
+ return false;
108
+ }
109
+ case 'list': {
110
+ if (baseOptional) {
111
+ return !(this.parent[this.meta.name] instanceof Array && this.parent[this.meta.name].length) && !this.meta.min;
112
+ }
113
+ return false;
114
+ }
115
+ default: {
116
+ return baseOptional && typeof(this.parent[this.meta.name]) === 'undefined';
117
+ }
118
+ }
119
+ }
120
+
121
+ static setup(instance, parent, meta) { } // eslint-disable-line @typescript-eslint/no-unused-vars
122
+
123
+ ngAfterViewInit() {
124
+ if (this.elementRef) {
125
+ if (this.integrationCode === 'mocks') {
126
+ this.integrationIcon = 'Brand-icon-vonage';
127
+ } else {
128
+ switch (this.integrationCode) {
129
+ case 'office365':
130
+ this.integrationIcon = 'Brand-icon-office-color';
131
+ break;
132
+ case 'sugar':
133
+ this.integrationIcon = 'Brand-icon-sugarcrm-color';
134
+ break;
135
+ case 'msdynamics':
136
+ this.integrationIcon = 'Brand-icon-dynamics-color';
137
+ break;
138
+ default:
139
+ this.integrationIcon = `Brand-icon-${(this.integrationCode || '').toLowerCase()}-color`;
140
+ }
141
+ }
142
+ Object.defineProperty(this.meta, '$optional', {
143
+ value: (typeof(this.default) === 'undefined') && this.isOptional,
144
+ writable: true,
145
+ configurable: true,
146
+ enumerable: false
147
+ });
148
+ this.flags = this.meta.flags || {};
149
+ Object.defineProperty(this.meta, '$hidden', {
150
+ value: !this.isPersistedParent && this.flags.creatable === false,
151
+ writable: true,
152
+ configurable: true,
153
+ enumerable: false
154
+ });
155
+ if (typeof(this.meta.hidden) !== 'undefined') {
156
+ if (typeof(this.meta.hidden) === 'object') {
157
+ const setHiddenByPropertyConfig = (par) => {
158
+ if (typeof(this.meta.hidden[par]) === 'boolean') { // any value makes me hidden
159
+ this.meta.$hidden = !!this.parent[par];
160
+ } else {
161
+ const value = extractValueBySmartProp(this.parent, par);
162
+ const parValue = value ? (value.id || value.value || value) : value;
163
+ this.meta.$hidden = this.meta.hidden[par] === parValue;
164
+ }
165
+ };
166
+ for (const par of Object.keys(this.meta.hidden)) {
167
+ setHiddenByPropertyConfig(par);
168
+ this.parentChangeSubject.subscribe((value) => {
169
+ if (value && value.hasOwnProperty(par.split('.')[0])) {
170
+ setHiddenByPropertyConfig(par);
171
+ if (this.meta.$hidden) {
172
+ delete this.parent[this.meta.name];
173
+ }
174
+ }
175
+ });
176
+ }
177
+ } else if (typeof(this.meta.hidden) === 'string') {
178
+ if (this.meta.hidden.toUpperCase() === 'CREATE') {
179
+ this.meta.$hidden = !this.isPersistedParent;
180
+ } else if (this.meta.hidden.toUpperCase() === 'UPDATE') {
181
+ this.meta.$hidden = this.isPersistedParent;
182
+ }
183
+ } else {
184
+ this.meta.$hidden= !!this.meta.hidden;
185
+ }
186
+ }
187
+
188
+ Object.defineProperty(this.meta, '$invisible', {
189
+ value: false,
190
+ writable: true,
191
+ configurable: true,
192
+ enumerable: false
193
+ });
194
+ if (typeof(this.meta.visible) !== 'undefined') {
195
+ if (typeof(this.meta.visible) === 'object') {
196
+ const setInvisibleByPropertyConfig = (par) => {
197
+ if (typeof(this.meta.visible[par]) === 'boolean') { // any value makes me hidden
198
+ this.meta.$invisible = extractBooleanValueBySmartProp(this.parent[par],this.meta.visible[par]);
199
+ } else {
200
+ const value = extractValueBySmartProp(this.parent, par);
201
+ const parValue = value ? (value.id || value.value || value) : value;
202
+ this.meta.$invisible = this.meta.visible[par] !== parValue;
203
+ }
204
+ };
205
+ for (const par of Object.keys(this.meta.visible)) {
206
+ setInvisibleByPropertyConfig(par);
207
+ this.parentChangeSubject.subscribe(() => {
208
+ // if (value && value.hasOwnProperty(par.split('.')[0])) {
209
+ setInvisibleByPropertyConfig(par);
210
+ if (this.meta.$invisible) {
211
+ delete this.parent[this.meta.name];
212
+ }
213
+ // }
214
+ });
215
+ }
216
+ } else if (typeof(this.meta.visible) === 'string') {
217
+ if (this.meta.visible.toUpperCase() === 'CREATE') {
218
+ this.meta.$invisible = this.isPersistedParent;
219
+ } else if (this.meta.visible.toUpperCase() === 'UPDATE') {
220
+ this.meta.$invisible = !this.isPersistedParent;
221
+ }
222
+ }
223
+ }
224
+
225
+ if (this.theme !== 'inherit') {
226
+ const metaTheme = this.theme === 'dark' ? metaDark : metaLight;
227
+ for (const key of Object.keys(metaTheme.properties)) {
228
+ this.elementRef.nativeElement.style.setProperty(key, metaTheme.properties[key]);
229
+ }
230
+ }
231
+ }
232
+ }
233
+
234
+ focus() {
235
+ const input = this.uiInput;
236
+ if (input) {
237
+ input.focus();
238
+ }
239
+ }
240
+
241
+ modelToValue(m, valueType) {
242
+ if (typeof(m) !== 'undefined') {
243
+ switch (valueType) {
244
+ case 'object': {
245
+ return m ? { id: m.id, label: m.label, type: m.type } : m;
246
+ }
247
+ case 'number': {
248
+ if (m != null) {
249
+ const v = m.id || m;
250
+ try {
251
+ return parseInt(v, 10);
252
+ } catch(e) {
253
+ if ((window as any).scDebug) console.error(e);
254
+ return v;
255
+ }
256
+ }
257
+ break;
258
+ }
259
+ default: {
260
+ if (m != null) {
261
+ return m.id || m;
262
+ }
263
+ }
264
+ }
265
+ }
266
+ }
267
+
268
+ onSubjectChange(model) {
269
+ if (Object.getOwnPropertyDescriptor(this.parent, '$changeSubject')) {
270
+ const parentChange: any = {};
271
+ parentChange[this.meta.name] = model;
272
+ this.parentChangeSubject.next(parentChange);
273
+ }
274
+ }
275
+
276
+ onModelChange(model) {
277
+ // TODO add resource type logic
278
+ if (this.model instanceof Array) {
279
+ this.parent[this.meta.name] = this.model.map((m) => this.modelToValue(m, this.meta.valueType));
280
+ } else {
281
+ this.parent[this.meta.name] = this.modelToValue(model, this.meta.valueType);
282
+ }
283
+ this.onChange.emit(model);
284
+ this.onSubjectChange(model);
285
+ // console.log('onChange', model);
286
+ this.changeEvent.initMouseEvent('change', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
287
+ this.elementRef.nativeElement.dispatchEvent(this.changeEvent);
288
+ if (this.model) {
289
+ this.prevModel = this.model;
290
+ } else {
291
+ this.meta.unset = true;
292
+ }
293
+ this.meta.$optional = this.isOptional;
294
+ }
295
+
296
+ clear() {
297
+ delete this.model;
298
+ this.onModelChange(this.model);
299
+ }
300
+
301
+ private applyValidations() {
302
+ this.validationAttributes.forEach((attribute) => {
303
+ const validation = this.validations[attribute];
304
+ if (validation) {
305
+ this.modelInput.setAttribute(attribute, validation.value || validation);
306
+ }
307
+ });
308
+ }
309
+ }
310
+
311
+
312
+ export class MetaElem {
313
+ csselem: string;
314
+ meta: any;
315
+ }
316
+
317
+ export abstract class MetaElemDisableadble implements MetaElem {
318
+ cssmodifier: string;
319
+ abstract meta: any;
320
+ abstract csselem: string;
321
+ abstract elementRef: ElementRef;
322
+ disable() {
323
+ console.log(this.cssmodifier);
324
+ this.elementRef.nativeElement.classList.remove(this.cssmodifier);
325
+ }
326
+ }
327
+
@@ -0,0 +1,55 @@
1
+ /*
2
+ * @Author: Alexander.Vangelov@vonage.com
3
+ * @Date: 2019-09-19 17:34:49
4
+ * @Last Modified by: Alexander.Vangelov@vonage.com
5
+ * @Last Modified time: 2020-03-26 12:57:51
6
+ */
7
+
8
+ import { Component, OnInit } from '@angular/core';
9
+ import { ControlContainer, NgForm } from '@angular/forms';
10
+
11
+ import { FieldAbstract } from '../fieldAbstract';
12
+ // import { tMetaField } from '../../../metaTypes/tMetaField'
13
+
14
+ @Component({
15
+ templateUrl: './view.html',
16
+ styleUrls: ['./style.scss'],
17
+ viewProviders: [{ provide: ControlContainer, useExisting: NgForm }],
18
+ standalone: false
19
+ })
20
+ export class FieldBoolean extends FieldAbstract implements OnInit {
21
+ // @Input() meta: any;
22
+ value: boolean;
23
+
24
+ ngOnInit() {
25
+ const origValue = this.parent[this.meta.name];
26
+ Object.defineProperty(this.parent, this.meta.name, {
27
+ set: (value) => {
28
+ if (typeof (value) === 'object' && value !== null) {
29
+ value = value.value || value.id || false;
30
+ }
31
+ if (!value && (typeof(this.prevModel) === 'boolean') && this.isPersistedParent) {
32
+ value = false;
33
+ }
34
+ this.model = (value === true) || (value != null && (['true', '1'].indexOf(value.toString().toLowerCase()) !== -1));
35
+ this.value = this.model;
36
+ this.meta.$optional = this.isOptional;
37
+ },
38
+ get: () => this.value,
39
+ enumerable: this.sendToServer,
40
+ configurable: true
41
+ });
42
+ if (typeof(origValue) !== 'undefined') {
43
+ this.parent[this.meta.name] = origValue;
44
+ }
45
+ if (typeof(this.meta.default) !== 'undefined' && typeof(this.model) === 'undefined' && !(this.meta.default instanceof Array)) {
46
+ setTimeout(() => {
47
+ this.onModelChange(this.meta.default);
48
+ }, 0);
49
+ }
50
+ }
51
+
52
+ onOptionChange() {
53
+ this.onModelChange(this.model);
54
+ }
55
+ }
@@ -0,0 +1,22 @@
1
+ .Vlt-checkbox + .Vlt-form__element__hint {
2
+ margin-top: 4px;
3
+ }
4
+ .Vlt-checkbox__button {
5
+ input {
6
+ &:not(:checked) ~ .Vlt-checkbox__icon {
7
+ background-color: var(--vgip-meta-input-bg-color);
8
+ border-color: var(--vgip-meta-input-border-color);
9
+ }
10
+ &:checked ~ .Vlt-checkbox__icon {
11
+ border-color: var(--vgip-meta-input-border-color);
12
+ }
13
+ }
14
+ input:hover, input:focus, input:active {
15
+ &:not(:checked) ~ .Vlt-checkbox__icon {
16
+ border-color: var(--vgip-meta-input-active-border-color);
17
+ }
18
+ &:checked ~ .Vlt-checkbox__icon {
19
+ border-color: var(--vgip-meta-input-accent-color);
20
+ }
21
+ }
22
+ }
@@ -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-15 10:52:54
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 { FieldBoolean } from '.';
14
+
15
+ describe('FieldInput', () => {
16
+ let component: FieldBoolean;
17
+ let fixture: ComponentFixture<FieldBoolean>;
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(FieldBoolean);
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
+ });
@@ -0,0 +1,30 @@
1
+ <div class='vgip-meta-field-preview' *ngIf='preview && model'>
2
+ <div class='vgip-meta-field-label' [title]='meta.label || meta.name'>{{meta.label || meta.name}}</div>
3
+ <div class='vgip-meta-field-value __gu'>
4
+ {{ model ? '✔' : '✘'}}
5
+ </div>
6
+ </div>
7
+ <div *ngIf='!preview' class="Vlt-form__element" [ngClass]="{ 'Vlt-form__element--error': f.invalid && ((f | metaModel)._parent.submitted || (f | metaModel ).touched) }">
8
+ <input class='model' type='hidden' [required]='validations.required' [(ngModel)]='model' #f='ngModel' [name]='name' />
9
+ <div class="Vlt-switch" *ngIf="meta.subtype === 'switch'">
10
+ <label style='vertical-align: middle;'>
11
+ <input class='model' type="checkbox" [(ngModel)]='model' (change)='onOptionChange()' [name]='name'/>
12
+ <span class="Vlt-switch__slider"></span>
13
+ <span style='margin-left: 60px; line-height: 30px; white-space: nowrap;'>{{meta.label || meta.name}}</span>
14
+ </label>
15
+ </div>
16
+ <div class="Vlt-checkbox" *ngIf="meta.subtype !== 'switch'">
17
+ <label style='cursor: pointer;'>
18
+ <span class="Vlt-checkbox__button">
19
+ <input class='model' type="checkbox" [(ngModel)]='model' (change)='onOptionChange()' [name]='name'/>
20
+ <span class="Vlt-checkbox__icon"></span>
21
+ </span>
22
+ {{meta.label || meta.name}}
23
+ </label>
24
+ </div>
25
+ <small *ngIf='f.invalid && ((f | metaModel)._parent.submitted || ((f | metaModel ).touched))' class="Vlt-form__element__error">
26
+ <span *ngIf="f.errors.required">Required</span>
27
+ <span *ngIf="f.errors.custom">{{f.errors.custom}}&nbsp;</span>
28
+ </small>
29
+ <small *ngIf='meta.hint' class="Vlt-form__element__hint">{{meta.hint}}</small>
30
+ </div>