@ng-formworks/core 15.2.7

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 (67) hide show
  1. package/karma.conf.js +46 -0
  2. package/ng-package.json +11 -0
  3. package/package.json +54 -0
  4. package/src/lib/framework-library/framework-library.service.ts +195 -0
  5. package/src/lib/framework-library/framework.ts +11 -0
  6. package/src/lib/framework-library/no-framework.component.html +2 -0
  7. package/src/lib/framework-library/no-framework.component.ts +11 -0
  8. package/src/lib/framework-library/no-framework.module.ts +18 -0
  9. package/src/lib/framework-library/no.framework.ts +11 -0
  10. package/src/lib/json-schema-form.component.html +7 -0
  11. package/src/lib/json-schema-form.component.ts +809 -0
  12. package/src/lib/json-schema-form.module.ts +17 -0
  13. package/src/lib/json-schema-form.service.ts +907 -0
  14. package/src/lib/locale/de-validation-messages.ts +58 -0
  15. package/src/lib/locale/en-validation-messages.ts +58 -0
  16. package/src/lib/locale/es-validation-messages.ts +55 -0
  17. package/src/lib/locale/fr-validation-messages.ts +58 -0
  18. package/src/lib/locale/index.ts +7 -0
  19. package/src/lib/locale/it-validation-messages.ts +58 -0
  20. package/src/lib/locale/pt-validation-messages.ts +58 -0
  21. package/src/lib/locale/zh-validation-messages.ts +58 -0
  22. package/src/lib/locale-dates/en-US.ts +5 -0
  23. package/src/lib/shared/convert-schema-to-draft6.function.ts +321 -0
  24. package/src/lib/shared/form-group.functions.ts +522 -0
  25. package/src/lib/shared/format-regex.constants.ts +73 -0
  26. package/src/lib/shared/index.ts +40 -0
  27. package/src/lib/shared/json-schema.functions.ts +788 -0
  28. package/src/lib/shared/json.validators.ts +878 -0
  29. package/src/lib/shared/jsonpointer.functions.ts +1012 -0
  30. package/src/lib/shared/jspointer.functions.json.spec.ts +103 -0
  31. package/src/lib/shared/layout.functions.ts +1233 -0
  32. package/src/lib/shared/merge-schemas.function.ts +329 -0
  33. package/src/lib/shared/utility.functions.ts +373 -0
  34. package/src/lib/shared/validator.functions.spec.ts +55 -0
  35. package/src/lib/shared/validator.functions.ts +601 -0
  36. package/src/lib/widget-library/add-reference.component.ts +59 -0
  37. package/src/lib/widget-library/button.component.ts +54 -0
  38. package/src/lib/widget-library/checkbox.component.ts +74 -0
  39. package/src/lib/widget-library/checkboxes.component.ts +104 -0
  40. package/src/lib/widget-library/file.component.ts +36 -0
  41. package/src/lib/widget-library/hidden.component.ts +39 -0
  42. package/src/lib/widget-library/index.ts +56 -0
  43. package/src/lib/widget-library/input.component.ts +76 -0
  44. package/src/lib/widget-library/message.component.ts +29 -0
  45. package/src/lib/widget-library/none.component.ts +12 -0
  46. package/src/lib/widget-library/number.component.ts +79 -0
  47. package/src/lib/widget-library/one-of.component.ts +36 -0
  48. package/src/lib/widget-library/orderable.directive.ts +130 -0
  49. package/src/lib/widget-library/radios.component.ts +101 -0
  50. package/src/lib/widget-library/root.component.ts +78 -0
  51. package/src/lib/widget-library/section.component.ts +133 -0
  52. package/src/lib/widget-library/select-framework.component.ts +50 -0
  53. package/src/lib/widget-library/select-widget.component.ts +46 -0
  54. package/src/lib/widget-library/select.component.ts +96 -0
  55. package/src/lib/widget-library/submit.component.ts +68 -0
  56. package/src/lib/widget-library/tab.component.ts +29 -0
  57. package/src/lib/widget-library/tabs.component.ts +83 -0
  58. package/src/lib/widget-library/template.component.ts +52 -0
  59. package/src/lib/widget-library/textarea.component.ts +68 -0
  60. package/src/lib/widget-library/widget-library.module.ts +13 -0
  61. package/src/lib/widget-library/widget-library.service.ts +234 -0
  62. package/src/public_api.ts +21 -0
  63. package/src/test.ts +18 -0
  64. package/tsconfig.lib.json +25 -0
  65. package/tsconfig.lib.prod.json +9 -0
  66. package/tsconfig.spec.json +17 -0
  67. package/tslint.json +11 -0
@@ -0,0 +1,130 @@
1
+ import {
2
+ Directive,
3
+ ElementRef,
4
+ Input,
5
+ NgZone,
6
+ OnInit
7
+ } from '@angular/core';
8
+ import { JsonSchemaFormService } from '../json-schema-form.service';
9
+
10
+
11
+ /**
12
+ * OrderableDirective
13
+ *
14
+ * Enables array elements to be reordered by dragging and dropping.
15
+ *
16
+ * Only works for arrays that have at least two elements.
17
+ *
18
+ * Also detects arrays-within-arrays, and correctly moves either
19
+ * the child array element or the parent array element,
20
+ * depending on the drop targert.
21
+ *
22
+ * Listeners for movable element being dragged:
23
+ * - dragstart: add 'dragging' class to element, set effectAllowed = 'move'
24
+ * - dragover: set dropEffect = 'move'
25
+ * - dragend: remove 'dragging' class from element
26
+ *
27
+ * Listeners for stationary items being dragged over:
28
+ * - dragenter: add 'drag-target-...' classes to element
29
+ * - dragleave: remove 'drag-target-...' classes from element
30
+ * - drop: remove 'drag-target-...' classes from element, move dropped array item
31
+ */
32
+ @Directive({
33
+ // tslint:disable-next-line:directive-selector
34
+ selector: '[orderable]',
35
+ })
36
+ export class OrderableDirective implements OnInit {
37
+ arrayLayoutIndex: string;
38
+ element: any;
39
+ overParentElement = false;
40
+ overChildElement = false;
41
+ @Input() orderable: boolean;
42
+ @Input() layoutNode: any;
43
+ @Input() layoutIndex: number[];
44
+ @Input() dataIndex: number[];
45
+
46
+ constructor(
47
+ private elementRef: ElementRef,
48
+ private jsf: JsonSchemaFormService,
49
+ private ngZone: NgZone
50
+ ) { }
51
+
52
+ ngOnInit() {
53
+ if (this.orderable && this.layoutNode && this.layoutIndex && this.dataIndex) {
54
+ this.element = this.elementRef.nativeElement;
55
+ this.element.draggable = true;
56
+ this.arrayLayoutIndex = 'move:' + this.layoutIndex.slice(0, -1).toString();
57
+
58
+ this.ngZone.runOutsideAngular(() => {
59
+
60
+ // Listeners for movable element being dragged:
61
+
62
+ this.element.addEventListener('dragstart', (event) => {
63
+ event.dataTransfer.effectAllowed = 'move';
64
+ event.dataTransfer.setData('text', '');
65
+ // Hack to bypass stupid HTML drag-and-drop dataTransfer protection
66
+ // so drag source info will be available on dragenter
67
+ const sourceArrayIndex = this.dataIndex[this.dataIndex.length - 1];
68
+ sessionStorage.setItem(this.arrayLayoutIndex, sourceArrayIndex + '');
69
+ });
70
+
71
+ this.element.addEventListener('dragover', (event) => {
72
+ if (event.preventDefault) { event.preventDefault(); }
73
+ event.dataTransfer.dropEffect = 'move';
74
+ return false;
75
+ });
76
+
77
+ // Listeners for stationary items being dragged over:
78
+
79
+ this.element.addEventListener('dragenter', (event) => {
80
+ // Part 1 of a hack, inspired by Dragster, to simulate mouseover and mouseout
81
+ // behavior while dragging items - http://bensmithett.github.io/dragster/
82
+ if (this.overParentElement) {
83
+ return this.overChildElement = true;
84
+ } else {
85
+ this.overParentElement = true;
86
+ }
87
+
88
+ const sourceArrayIndex = sessionStorage.getItem(this.arrayLayoutIndex);
89
+ if (sourceArrayIndex !== null) {
90
+ if (this.dataIndex[this.dataIndex.length - 1] < +sourceArrayIndex) {
91
+ this.element.classList.add('drag-target-top');
92
+ } else if (this.dataIndex[this.dataIndex.length - 1] > +sourceArrayIndex) {
93
+ this.element.classList.add('drag-target-bottom');
94
+ }
95
+ }
96
+ });
97
+
98
+ this.element.addEventListener('dragleave', (event) => {
99
+ // Part 2 of the Dragster hack
100
+ if (this.overChildElement) {
101
+ this.overChildElement = false;
102
+ } else if (this.overParentElement) {
103
+ this.overParentElement = false;
104
+ }
105
+
106
+ const sourceArrayIndex = sessionStorage.getItem(this.arrayLayoutIndex);
107
+ if (!this.overParentElement && !this.overChildElement && sourceArrayIndex !== null) {
108
+ this.element.classList.remove('drag-target-top');
109
+ this.element.classList.remove('drag-target-bottom');
110
+ }
111
+ });
112
+
113
+ this.element.addEventListener('drop', (event) => {
114
+ this.element.classList.remove('drag-target-top');
115
+ this.element.classList.remove('drag-target-bottom');
116
+ // Confirm that drop target is another item in the same array as source item
117
+ const sourceArrayIndex = sessionStorage.getItem(this.arrayLayoutIndex);
118
+ const destArrayIndex = this.dataIndex[this.dataIndex.length - 1];
119
+ if (sourceArrayIndex !== null && +sourceArrayIndex !== destArrayIndex) {
120
+ // Move array item
121
+ this.jsf.moveArrayItem(this, +sourceArrayIndex, destArrayIndex);
122
+ }
123
+ sessionStorage.removeItem(this.arrayLayoutIndex);
124
+ return false;
125
+ });
126
+
127
+ });
128
+ }
129
+ }
130
+ }
@@ -0,0 +1,101 @@
1
+ import { AbstractControl } from '@angular/forms';
2
+ import { buildTitleMap } from '../shared';
3
+ import { Component, Input, OnInit } from '@angular/core';
4
+ import { JsonSchemaFormService } from '../json-schema-form.service';
5
+
6
+
7
+ @Component({
8
+ // tslint:disable-next-line:component-selector
9
+ selector: 'radios-widget',
10
+ template: `
11
+ <label *ngIf="options?.title"
12
+ [attr.for]="'control' + layoutNode?._id"
13
+ [class]="options?.labelHtmlClass || ''"
14
+ [style.display]="options?.notitle ? 'none' : ''"
15
+ [innerHTML]="options?.title"></label>
16
+
17
+ <!-- 'horizontal' = radios-inline or radiobuttons -->
18
+ <div *ngIf="layoutOrientation === 'horizontal'"
19
+ [class]="options?.htmlClass || ''">
20
+ <label *ngFor="let radioItem of radiosList"
21
+ [attr.for]="'control' + layoutNode?._id + '/' + radioItem?.value"
22
+ [class]="(options?.itemLabelHtmlClass || '') +
23
+ ((controlValue + '' === radioItem?.value + '') ?
24
+ (' ' + (options?.activeClass || '') + ' ' + (options?.style?.selected || '')) :
25
+ (' ' + (options?.style?.unselected || '')))">
26
+ <input type="radio"
27
+ [attr.aria-describedby]="'control' + layoutNode?._id + 'Status'"
28
+ [attr.readonly]="options?.readonly ? 'readonly' : null"
29
+ [attr.required]="options?.required"
30
+ [checked]="radioItem?.value === controlValue"
31
+ [class]="options?.fieldHtmlClass || ''"
32
+ [disabled]="controlDisabled"
33
+ [id]="'control' + layoutNode?._id + '/' + radioItem?.value"
34
+ [name]="controlName"
35
+ [value]="radioItem?.value"
36
+ (change)="updateValue($event)">
37
+ <span [innerHTML]="radioItem?.name"></span>
38
+ </label>
39
+ </div>
40
+
41
+ <!-- 'vertical' = regular radios -->
42
+ <div *ngIf="layoutOrientation !== 'horizontal'">
43
+ <div *ngFor="let radioItem of radiosList"
44
+ [class]="options?.htmlClass || ''">
45
+ <label
46
+ [attr.for]="'control' + layoutNode?._id + '/' + radioItem?.value"
47
+ [class]="(options?.itemLabelHtmlClass || '') +
48
+ ((controlValue + '' === radioItem?.value + '') ?
49
+ (' ' + (options?.activeClass || '') + ' ' + (options?.style?.selected || '')) :
50
+ (' ' + (options?.style?.unselected || '')))">
51
+ <input type="radio"
52
+ [attr.aria-describedby]="'control' + layoutNode?._id + 'Status'"
53
+ [attr.readonly]="options?.readonly ? 'readonly' : null"
54
+ [attr.required]="options?.required"
55
+ [checked]="radioItem?.value === controlValue"
56
+ [class]="options?.fieldHtmlClass || ''"
57
+ [disabled]="controlDisabled"
58
+ [id]="'control' + layoutNode?._id + '/' + radioItem?.value"
59
+ [name]="controlName"
60
+ [value]="radioItem?.value"
61
+ (change)="updateValue($event)">
62
+ <span [innerHTML]="radioItem?.name"></span>
63
+ </label>
64
+ </div>
65
+ </div>`,
66
+ })
67
+ export class RadiosComponent implements OnInit {
68
+ formControl: AbstractControl;
69
+ controlName: string;
70
+ controlValue: any;
71
+ controlDisabled = false;
72
+ boundControl = false;
73
+ options: any;
74
+ layoutOrientation = 'vertical';
75
+ radiosList: any[] = [];
76
+ @Input() layoutNode: any;
77
+ @Input() layoutIndex: number[];
78
+ @Input() dataIndex: number[];
79
+
80
+ constructor(
81
+ private jsf: JsonSchemaFormService
82
+ ) { }
83
+
84
+ ngOnInit() {
85
+ this.options = this.layoutNode.options || {};
86
+ if (this.layoutNode.type === 'radios-inline' ||
87
+ this.layoutNode.type === 'radiobuttons'
88
+ ) {
89
+ this.layoutOrientation = 'horizontal';
90
+ }
91
+ this.radiosList = buildTitleMap(
92
+ this.options.titleMap || this.options.enumNames,
93
+ this.options.enum, true
94
+ );
95
+ this.jsf.initializeControl(this);
96
+ }
97
+
98
+ updateValue(event) {
99
+ this.jsf.updateValue(this, event.target.value);
100
+ }
101
+ }
@@ -0,0 +1,78 @@
1
+ import { Component, Input } from '@angular/core';
2
+ import { JsonSchemaFormService } from '../json-schema-form.service';
3
+
4
+
5
+ @Component({
6
+ // tslint:disable-next-line:component-selector
7
+ selector: 'root-widget',
8
+ template: `
9
+ <div *ngFor="let layoutItem of layout; let i = index"
10
+ [class.form-flex-item]="isFlexItem"
11
+ [style.align-self]="(layoutItem.options || {})['align-self']"
12
+ [style.flex-basis]="getFlexAttribute(layoutItem, 'flex-basis')"
13
+ [style.flex-grow]="getFlexAttribute(layoutItem, 'flex-grow')"
14
+ [style.flex-shrink]="getFlexAttribute(layoutItem, 'flex-shrink')"
15
+ [style.order]="(layoutItem.options || {}).order">
16
+ <div
17
+ [dataIndex]="layoutItem?.arrayItem ? (dataIndex || []).concat(i) : (dataIndex || [])"
18
+ [layoutIndex]="(layoutIndex || []).concat(i)"
19
+ [layoutNode]="layoutItem"
20
+ [orderable]="isDraggable(layoutItem)">
21
+ <select-framework-widget *ngIf="showWidget(layoutItem)"
22
+ [dataIndex]="layoutItem?.arrayItem ? (dataIndex || []).concat(i) : (dataIndex || [])"
23
+ [layoutIndex]="(layoutIndex || []).concat(i)"
24
+ [layoutNode]="layoutItem"></select-framework-widget>
25
+ </div>
26
+ </div>`,
27
+ styles: [`
28
+ [draggable=true] {
29
+ transition: all 150ms cubic-bezier(.4, 0, .2, 1);
30
+ }
31
+ [draggable=true]:hover {
32
+ cursor: move;
33
+ box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);
34
+ position: relative; z-index: 10;
35
+ margin-top: -1px;
36
+ margin-left: -1px;
37
+ margin-right: 1px;
38
+ margin-bottom: 1px;
39
+ }
40
+ [draggable=true].drag-target-top {
41
+ box-shadow: 0 -2px 0 #000;
42
+ position: relative; z-index: 20;
43
+ }
44
+ [draggable=true].drag-target-bottom {
45
+ box-shadow: 0 2px 0 #000;
46
+ position: relative; z-index: 20;
47
+ }
48
+ `],
49
+ })
50
+ export class RootComponent {
51
+ options: any;
52
+ @Input() dataIndex: number[];
53
+ @Input() layoutIndex: number[];
54
+ @Input() layout: any[];
55
+ @Input() isOrderable: boolean;
56
+ @Input() isFlexItem = false;
57
+
58
+ constructor(
59
+ private jsf: JsonSchemaFormService
60
+ ) { }
61
+
62
+ isDraggable(node: any): boolean {
63
+ return node.arrayItem && node.type !== '$ref' &&
64
+ node.arrayItemType === 'list' && this.isOrderable !== false;
65
+ }
66
+
67
+ // Set attributes for flexbox child
68
+ // (container attributes are set in section.component)
69
+ getFlexAttribute(node: any, attribute: string) {
70
+ const index = ['flex-grow', 'flex-shrink', 'flex-basis'].indexOf(attribute);
71
+ return ((node.options || {}).flex || '').split(/\s+/)[index] ||
72
+ (node.options || {})[attribute] || ['1', '1', 'auto'][index];
73
+ }
74
+
75
+ showWidget(layoutNode: any): boolean {
76
+ return this.jsf.evaluateCondition(layoutNode, this.dataIndex);
77
+ }
78
+ }
@@ -0,0 +1,133 @@
1
+ import { Component, Input, OnInit } from '@angular/core';
2
+ import { JsonSchemaFormService } from '../json-schema-form.service';
3
+
4
+
5
+ @Component({
6
+ // tslint:disable-next-line:component-selector
7
+ selector: 'section-widget',
8
+ template: `
9
+ <div *ngIf="containerType === 'div'"
10
+ [class]="options?.htmlClass || ''"
11
+ [class.expandable]="options?.expandable && !expanded"
12
+ [class.expanded]="options?.expandable && expanded">
13
+ <label *ngIf="sectionTitle"
14
+ class="legend"
15
+ [class]="options?.labelHtmlClass || ''"
16
+ [innerHTML]="sectionTitle"
17
+ (click)="toggleExpanded()"></label>
18
+ <root-widget *ngIf="expanded"
19
+ [dataIndex]="dataIndex"
20
+ [layout]="layoutNode.items"
21
+ [layoutIndex]="layoutIndex"
22
+ [isFlexItem]="getFlexAttribute('is-flex')"
23
+ [isOrderable]="options?.orderable"
24
+ [class.form-flex-column]="getFlexAttribute('flex-direction') === 'column'"
25
+ [class.form-flex-row]="getFlexAttribute('flex-direction') === 'row'"
26
+ [style.align-content]="getFlexAttribute('align-content')"
27
+ [style.align-items]="getFlexAttribute('align-items')"
28
+ [style.display]="getFlexAttribute('display')"
29
+ [style.flex-direction]="getFlexAttribute('flex-direction')"
30
+ [style.flex-wrap]="getFlexAttribute('flex-wrap')"
31
+ [style.justify-content]="getFlexAttribute('justify-content')"></root-widget>
32
+ </div>
33
+ <fieldset *ngIf="containerType === 'fieldset'"
34
+ [class]="options?.htmlClass || ''"
35
+ [class.expandable]="options?.expandable && !expanded"
36
+ [class.expanded]="options?.expandable && expanded"
37
+ [disabled]="options?.readonly">
38
+ <legend *ngIf="sectionTitle"
39
+ class="legend"
40
+ [class]="options?.labelHtmlClass || ''"
41
+ [innerHTML]="sectionTitle"
42
+ (click)="toggleExpanded()"></legend>
43
+ <div *ngIf="options?.messageLocation !== 'bottom'">
44
+ <p *ngIf="options?.description"
45
+ class="help-block"
46
+ [class]="options?.labelHelpBlockClass || ''"
47
+ [innerHTML]="options?.description"></p>
48
+ </div>
49
+ <root-widget *ngIf="expanded"
50
+ [dataIndex]="dataIndex"
51
+ [layout]="layoutNode.items"
52
+ [layoutIndex]="layoutIndex"
53
+ [isFlexItem]="getFlexAttribute('is-flex')"
54
+ [isOrderable]="options?.orderable"
55
+ [class.form-flex-column]="getFlexAttribute('flex-direction') === 'column'"
56
+ [class.form-flex-row]="getFlexAttribute('flex-direction') === 'row'"
57
+ [style.align-content]="getFlexAttribute('align-content')"
58
+ [style.align-items]="getFlexAttribute('align-items')"
59
+ [style.display]="getFlexAttribute('display')"
60
+ [style.flex-direction]="getFlexAttribute('flex-direction')"
61
+ [style.flex-wrap]="getFlexAttribute('flex-wrap')"
62
+ [style.justify-content]="getFlexAttribute('justify-content')"></root-widget>
63
+ <div *ngIf="options?.messageLocation === 'bottom'">
64
+ <p *ngIf="options?.description"
65
+ class="help-block"
66
+ [class]="options?.labelHelpBlockClass || ''"
67
+ [innerHTML]="options?.description"></p>
68
+ </div>
69
+ </fieldset>`,
70
+ styles: [`
71
+ .legend { font-weight: bold; }
72
+ .expandable > legend:before, .expandable > label:before { content: '▶'; padding-right: .3em; }
73
+ .expanded > legend:before, .expanded > label:before { content: '▼'; padding-right: .2em; }
74
+ `],
75
+ })
76
+ export class SectionComponent implements OnInit {
77
+ options: any;
78
+ expanded = true;
79
+ containerType: string;
80
+ @Input() layoutNode: any;
81
+ @Input() layoutIndex: number[];
82
+ @Input() dataIndex: number[];
83
+
84
+ constructor(
85
+ private jsf: JsonSchemaFormService
86
+ ) { }
87
+
88
+ get sectionTitle() {
89
+ return this.options.notitle ? null : this.jsf.setItemTitle(this);
90
+ }
91
+
92
+ ngOnInit() {
93
+ this.jsf.initializeControl(this);
94
+ this.options = this.layoutNode.options || {};
95
+ this.expanded = typeof this.options.expanded === 'boolean' ?
96
+ this.options.expanded : !this.options.expandable;
97
+ switch (this.layoutNode.type) {
98
+ case 'fieldset': case 'array': case 'tab': case 'advancedfieldset':
99
+ case 'authfieldset': case 'optionfieldset': case 'selectfieldset':
100
+ this.containerType = 'fieldset';
101
+ break;
102
+ default: // 'div', 'flex', 'section', 'conditional', 'actions', 'tagsinput'
103
+ this.containerType = 'div';
104
+ break;
105
+ }
106
+ }
107
+
108
+ toggleExpanded() {
109
+ if (this.options.expandable) { this.expanded = !this.expanded; }
110
+ }
111
+
112
+ // Set attributes for flexbox container
113
+ // (child attributes are set in root.component)
114
+ getFlexAttribute(attribute: string) {
115
+ const flexActive: boolean =
116
+ this.layoutNode.type === 'flex' ||
117
+ !!this.options.displayFlex ||
118
+ this.options.display === 'flex';
119
+ if (attribute !== 'flex' && !flexActive) { return null; }
120
+ switch (attribute) {
121
+ case 'is-flex':
122
+ return flexActive;
123
+ case 'display':
124
+ return flexActive ? 'flex' : 'initial';
125
+ case 'flex-direction': case 'flex-wrap':
126
+ const index = ['flex-direction', 'flex-wrap'].indexOf(attribute);
127
+ return (this.options['flex-flow'] || '').split(/\s+/)[index] ||
128
+ this.options[attribute] || ['column', 'nowrap'][index];
129
+ case 'justify-content': case 'align-items': case 'align-content':
130
+ return this.options[attribute];
131
+ }
132
+ }
133
+ }
@@ -0,0 +1,50 @@
1
+ import {
2
+ Component, ComponentFactoryResolver, ComponentRef, Input,
3
+ OnChanges, OnInit, ViewChild, ViewContainerRef
4
+ } from '@angular/core';
5
+
6
+ import { JsonSchemaFormService } from '../json-schema-form.service';
7
+
8
+ @Component({
9
+ // tslint:disable-next-line:component-selector
10
+ selector: 'select-framework-widget',
11
+ template: `<div #widgetContainer></div>`,
12
+ })
13
+ export class SelectFrameworkComponent implements OnChanges, OnInit {
14
+ newComponent: ComponentRef<any> = null;
15
+ @Input() layoutNode: any;
16
+ @Input() layoutIndex: number[];
17
+ @Input() dataIndex: number[];
18
+ @ViewChild('widgetContainer', {
19
+ read: ViewContainerRef,
20
+ static: true })
21
+ widgetContainer: ViewContainerRef;
22
+
23
+ constructor(
24
+ private componentFactory: ComponentFactoryResolver,
25
+ private jsf: JsonSchemaFormService
26
+ ) { }
27
+
28
+ ngOnInit() {
29
+ this.updateComponent();
30
+ }
31
+
32
+ ngOnChanges() {
33
+ this.updateComponent();
34
+ }
35
+
36
+ updateComponent() {
37
+ if (this.widgetContainer && !this.newComponent && this.jsf.framework) {
38
+ this.newComponent = this.widgetContainer.createComponent(
39
+ this.componentFactory.resolveComponentFactory(this.jsf.framework)
40
+ );
41
+ //TODO fix all deprecated calls and test
42
+ //this.widgetContainer.createComponent<any>(this.jsf.framework)
43
+ }
44
+ if (this.newComponent) {
45
+ for (const input of ['layoutNode', 'layoutIndex', 'dataIndex']) {
46
+ this.newComponent.instance[input] = this[input];
47
+ }
48
+ }
49
+ }
50
+ }
@@ -0,0 +1,46 @@
1
+ import {
2
+ Component, ComponentFactoryResolver, ComponentRef, Input,
3
+ OnChanges, OnInit, ViewChild, ViewContainerRef
4
+ } from '@angular/core';
5
+
6
+ import { JsonSchemaFormService } from '../json-schema-form.service';
7
+
8
+ @Component({
9
+ // tslint:disable-next-line:component-selector
10
+ selector: 'select-widget-widget',
11
+ template: `<div #widgetContainer></div>`,
12
+ })
13
+ export class SelectWidgetComponent implements OnChanges, OnInit {
14
+ newComponent: ComponentRef<any> = null;
15
+ @Input() layoutNode: any;
16
+ @Input() layoutIndex: number[];
17
+ @Input() dataIndex: number[];
18
+ @ViewChild('widgetContainer', { read: ViewContainerRef, static: true })
19
+ widgetContainer: ViewContainerRef;
20
+
21
+ constructor(
22
+ private componentFactory: ComponentFactoryResolver,
23
+ private jsf: JsonSchemaFormService
24
+ ) { }
25
+
26
+ ngOnInit() {
27
+ this.updateComponent();
28
+ }
29
+
30
+ ngOnChanges() {
31
+ this.updateComponent();
32
+ }
33
+
34
+ updateComponent() {
35
+ if (this.widgetContainer && !this.newComponent && (this.layoutNode || {}).widget) {
36
+ this.newComponent = this.widgetContainer.createComponent(
37
+ this.componentFactory.resolveComponentFactory(this.layoutNode.widget)
38
+ );
39
+ }
40
+ if (this.newComponent) {
41
+ for (const input of ['layoutNode', 'layoutIndex', 'dataIndex']) {
42
+ this.newComponent.instance[input] = this[input];
43
+ }
44
+ }
45
+ }
46
+ }
@@ -0,0 +1,96 @@
1
+ import { AbstractControl } from '@angular/forms';
2
+ import { buildTitleMap, isArray } from '../shared';
3
+ import { Component, Input, OnInit } from '@angular/core';
4
+ import { JsonSchemaFormService } from '../json-schema-form.service';
5
+
6
+
7
+ @Component({
8
+ // tslint:disable-next-line:component-selector
9
+ selector: 'select-widget',
10
+ template: `
11
+ <div
12
+ [class]="options?.htmlClass || ''">
13
+ <label *ngIf="options?.title"
14
+ [attr.for]="'control' + layoutNode?._id"
15
+ [class]="options?.labelHtmlClass || ''"
16
+ [style.display]="options?.notitle ? 'none' : ''"
17
+ [innerHTML]="options?.title"></label>
18
+ <select *ngIf="boundControl"
19
+ [formControl]="formControl"
20
+ [attr.aria-describedby]="'control' + layoutNode?._id + 'Status'"
21
+ [attr.readonly]="options?.readonly ? 'readonly' : null"
22
+ [attr.required]="options?.required"
23
+ [class]="options?.fieldHtmlClass || ''"
24
+ [id]="'control' + layoutNode?._id"
25
+ [name]="controlName">
26
+ <ng-template ngFor let-selectItem [ngForOf]="selectList">
27
+ <option *ngIf="!isArray(selectItem?.items)"
28
+ [value]="selectItem?.value">
29
+ <span [innerHTML]="selectItem?.name"></span>
30
+ </option>
31
+ <optgroup *ngIf="isArray(selectItem?.items)"
32
+ [label]="selectItem?.group">
33
+ <option *ngFor="let subItem of selectItem.items"
34
+ [value]="subItem?.value">
35
+ <span [innerHTML]="subItem?.name"></span>
36
+ </option>
37
+ </optgroup>
38
+ </ng-template>
39
+ </select>
40
+ <select *ngIf="!boundControl"
41
+ [attr.aria-describedby]="'control' + layoutNode?._id + 'Status'"
42
+ [attr.readonly]="options?.readonly ? 'readonly' : null"
43
+ [attr.required]="options?.required"
44
+ [class]="options?.fieldHtmlClass || ''"
45
+ [disabled]="controlDisabled"
46
+ [id]="'control' + layoutNode?._id"
47
+ [name]="controlName"
48
+ (change)="updateValue($event)">
49
+ <ng-template ngFor let-selectItem [ngForOf]="selectList">
50
+ <option *ngIf="!isArray(selectItem?.items)"
51
+ [selected]="selectItem?.value === controlValue"
52
+ [value]="selectItem?.value">
53
+ <span [innerHTML]="selectItem?.name"></span>
54
+ </option>
55
+ <optgroup *ngIf="isArray(selectItem?.items)"
56
+ [label]="selectItem?.group">
57
+ <option *ngFor="let subItem of selectItem.items"
58
+ [attr.selected]="subItem?.value === controlValue"
59
+ [value]="subItem?.value">
60
+ <span [innerHTML]="subItem?.name"></span>
61
+ </option>
62
+ </optgroup>
63
+ </ng-template>
64
+ </select>
65
+ </div>`,
66
+ })
67
+ export class SelectComponent implements OnInit {
68
+ formControl: AbstractControl;
69
+ controlName: string;
70
+ controlValue: any;
71
+ controlDisabled = false;
72
+ boundControl = false;
73
+ options: any;
74
+ selectList: any[] = [];
75
+ isArray = isArray;
76
+ @Input() layoutNode: any;
77
+ @Input() layoutIndex: number[];
78
+ @Input() dataIndex: number[];
79
+
80
+ constructor(
81
+ private jsf: JsonSchemaFormService
82
+ ) { }
83
+
84
+ ngOnInit() {
85
+ this.options = this.layoutNode.options || {};
86
+ this.selectList = buildTitleMap(
87
+ this.options.titleMap || this.options.enumNames,
88
+ this.options.enum, !!this.options.required, !!this.options.flatList
89
+ );
90
+ this.jsf.initializeControl(this);
91
+ }
92
+
93
+ updateValue(event) {
94
+ this.jsf.updateValue(this, event.target.value);
95
+ }
96
+ }