@ng-formworks/core 17.2.7 → 18.0.0
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.
- package/LICENSE +21 -0
- package/README.md +834 -0
- package/esm2022/lib/framework-library/framework-library.service.mjs +175 -0
- package/esm2022/lib/framework-library/framework.mjs +15 -0
- package/esm2022/lib/framework-library/no-framework.component.mjs +18 -0
- package/esm2022/lib/framework-library/no-framework.module.mjs +27 -0
- package/esm2022/lib/framework-library/no.framework.mjs +19 -0
- package/esm2022/lib/json-schema-form.component.mjs +765 -0
- package/esm2022/lib/json-schema-form.module.mjs +26 -0
- package/esm2022/lib/json-schema-form.service.mjs +676 -0
- package/esm2022/lib/locale/de-validation-messages.mjs +60 -0
- package/esm2022/lib/locale/en-validation-messages.mjs +60 -0
- package/esm2022/lib/locale/es-validation-messages.mjs +57 -0
- package/esm2022/lib/locale/fr-validation-messages.mjs +60 -0
- package/esm2022/lib/locale/index.mjs +8 -0
- package/esm2022/lib/locale/it-validation-messages.mjs +60 -0
- package/esm2022/lib/locale/pt-validation-messages.mjs +60 -0
- package/esm2022/lib/locale/zh-validation-messages.mjs +60 -0
- package/esm2022/lib/shared/convert-schema-to-draft6.function.mjs +300 -0
- package/esm2022/lib/shared/form-group.functions.mjs +442 -0
- package/esm2022/lib/shared/format-regex.constants.mjs +54 -0
- package/esm2022/lib/shared/index.mjs +12 -0
- package/esm2022/lib/shared/json-schema.functions.mjs +784 -0
- package/esm2022/lib/shared/json.validators.mjs +884 -0
- package/esm2022/lib/shared/jsonpointer.functions.mjs +1026 -0
- package/esm2022/lib/shared/layout.functions.mjs +1158 -0
- package/esm2022/lib/shared/merge-schemas.function.mjs +345 -0
- package/esm2022/lib/shared/utility.functions.mjs +380 -0
- package/esm2022/lib/shared/validator.functions.mjs +584 -0
- package/esm2022/lib/widget-library/add-reference.component.mjs +61 -0
- package/esm2022/lib/widget-library/button.component.mjs +72 -0
- package/esm2022/lib/widget-library/checkbox.component.mjs +105 -0
- package/esm2022/lib/widget-library/checkboxes.component.mjs +147 -0
- package/esm2022/lib/widget-library/file.component.mjs +35 -0
- package/esm2022/lib/widget-library/hidden.component.mjs +54 -0
- package/esm2022/lib/widget-library/index.mjs +55 -0
- package/esm2022/lib/widget-library/input.component.mjs +119 -0
- package/esm2022/lib/widget-library/message.component.mjs +38 -0
- package/esm2022/lib/widget-library/none.component.mjs +21 -0
- package/esm2022/lib/widget-library/number.component.mjs +123 -0
- package/esm2022/lib/widget-library/one-of.component.mjs +35 -0
- package/esm2022/lib/widget-library/orderable.directive.mjs +123 -0
- package/esm2022/lib/widget-library/radios.component.mjs +153 -0
- package/esm2022/lib/widget-library/root.component.mjs +79 -0
- package/esm2022/lib/widget-library/section.component.mjs +199 -0
- package/esm2022/lib/widget-library/select-framework.component.mjs +51 -0
- package/esm2022/lib/widget-library/select-widget.component.mjs +46 -0
- package/esm2022/lib/widget-library/select.component.mjs +150 -0
- package/esm2022/lib/widget-library/submit.component.mjs +82 -0
- package/esm2022/lib/widget-library/tab.component.mjs +41 -0
- package/esm2022/lib/widget-library/tabs.component.mjs +108 -0
- package/esm2022/lib/widget-library/template.component.mjs +46 -0
- package/esm2022/lib/widget-library/textarea.component.mjs +104 -0
- package/esm2022/lib/widget-library/widget-library.module.mjs +42 -0
- package/esm2022/lib/widget-library/widget-library.service.mjs +226 -0
- package/esm2022/ng-formworks-core.mjs +5 -0
- package/esm2022/public_api.mjs +13 -0
- package/fesm2022/ng-formworks-core.mjs +10151 -0
- package/fesm2022/ng-formworks-core.mjs.map +1 -0
- package/index.d.ts +5 -0
- package/lib/framework-library/framework-library.service.d.ts +55 -0
- package/lib/framework-library/framework.d.ts +13 -0
- package/lib/framework-library/no-framework.component.d.ts +8 -0
- package/lib/framework-library/no-framework.module.d.ts +9 -0
- package/lib/framework-library/no.framework.d.ts +10 -0
- package/lib/json-schema-form.component.d.ts +218 -0
- package/lib/json-schema-form.module.d.ts +11 -0
- package/lib/json-schema-form.service.d.ts +115 -0
- package/lib/locale/de-validation-messages.d.ts +1 -0
- package/lib/locale/en-validation-messages.d.ts +1 -0
- package/lib/locale/es-validation-messages.d.ts +1 -0
- package/lib/locale/fr-validation-messages.d.ts +1 -0
- package/{src/lib/locale/index.ts → lib/locale/index.d.ts} +7 -7
- package/lib/locale/it-validation-messages.d.ts +1 -0
- package/lib/locale/pt-validation-messages.d.ts +1 -0
- package/lib/locale/zh-validation-messages.d.ts +1 -0
- package/lib/shared/convert-schema-to-draft6.function.d.ts +21 -0
- package/lib/shared/form-group.functions.d.ts +100 -0
- package/lib/shared/format-regex.constants.d.ts +19 -0
- package/lib/shared/index.d.ts +9 -0
- package/lib/shared/json-schema.functions.d.ts +193 -0
- package/lib/shared/json.validators.d.ts +441 -0
- package/lib/shared/jsonpointer.functions.d.ts +416 -0
- package/lib/shared/layout.functions.d.ts +83 -0
- package/lib/shared/merge-schemas.function.d.ts +19 -0
- package/lib/shared/utility.functions.d.ts +165 -0
- package/{src/lib/shared/validator.functions.ts → lib/shared/validator.functions.d.ts} +364 -601
- package/lib/widget-library/add-reference.component.d.ts +20 -0
- package/lib/widget-library/button.component.d.ts +21 -0
- package/lib/widget-library/checkbox.component.d.ts +24 -0
- package/lib/widget-library/checkboxes.component.d.ts +24 -0
- package/lib/widget-library/file.component.d.ts +21 -0
- package/lib/widget-library/hidden.component.d.ts +19 -0
- package/{src/lib/widget-library/index.ts → lib/widget-library/index.d.ts} +47 -56
- package/lib/widget-library/input.component.d.ts +22 -0
- package/lib/widget-library/message.component.d.ts +15 -0
- package/lib/widget-library/none.component.d.ts +8 -0
- package/lib/widget-library/number.component.d.ts +25 -0
- package/lib/widget-library/one-of.component.d.ts +21 -0
- package/lib/widget-library/orderable.directive.d.ts +41 -0
- package/lib/widget-library/radios.component.d.ts +23 -0
- package/lib/widget-library/root.component.d.ts +17 -0
- package/lib/widget-library/section.component.d.ts +19 -0
- package/lib/widget-library/select-framework.component.d.ts +18 -0
- package/lib/widget-library/select-widget.component.d.ts +18 -0
- package/lib/widget-library/select.component.d.ts +24 -0
- package/lib/widget-library/submit.component.d.ts +24 -0
- package/lib/widget-library/tab.component.d.ts +14 -0
- package/lib/widget-library/tabs.component.d.ts +20 -0
- package/lib/widget-library/template.component.d.ts +18 -0
- package/lib/widget-library/textarea.component.d.ts +21 -0
- package/lib/widget-library/widget-library.module.d.ts +31 -0
- package/lib/widget-library/widget-library.service.d.ts +22 -0
- package/package.json +66 -53
- package/{src/public_api.ts → public_api.d.ts} +9 -21
- package/karma.conf.js +0 -46
- package/ng-package.json +0 -11
- package/src/lib/framework-library/framework-library.service.ts +0 -195
- package/src/lib/framework-library/framework.ts +0 -11
- package/src/lib/framework-library/no-framework.component.html +0 -2
- package/src/lib/framework-library/no-framework.component.ts +0 -11
- package/src/lib/framework-library/no-framework.module.ts +0 -18
- package/src/lib/framework-library/no.framework.ts +0 -11
- package/src/lib/json-schema-form.component.html +0 -7
- package/src/lib/json-schema-form.component.ts +0 -809
- package/src/lib/json-schema-form.module.ts +0 -17
- package/src/lib/json-schema-form.service.ts +0 -907
- package/src/lib/locale/de-validation-messages.ts +0 -58
- package/src/lib/locale/en-validation-messages.ts +0 -58
- package/src/lib/locale/es-validation-messages.ts +0 -55
- package/src/lib/locale/fr-validation-messages.ts +0 -58
- package/src/lib/locale/it-validation-messages.ts +0 -58
- package/src/lib/locale/pt-validation-messages.ts +0 -58
- package/src/lib/locale/zh-validation-messages.ts +0 -58
- package/src/lib/locale-dates/en-US.ts +0 -5
- package/src/lib/shared/convert-schema-to-draft6.function.ts +0 -321
- package/src/lib/shared/form-group.functions.ts +0 -522
- package/src/lib/shared/format-regex.constants.ts +0 -73
- package/src/lib/shared/index.ts +0 -40
- package/src/lib/shared/json-schema.functions.ts +0 -788
- package/src/lib/shared/json.validators.ts +0 -878
- package/src/lib/shared/jsonpointer.functions.ts +0 -1012
- package/src/lib/shared/jspointer.functions.json.spec.ts +0 -103
- package/src/lib/shared/layout.functions.ts +0 -1233
- package/src/lib/shared/merge-schemas.function.ts +0 -329
- package/src/lib/shared/utility.functions.ts +0 -373
- package/src/lib/shared/validator.functions.spec.ts +0 -55
- package/src/lib/widget-library/add-reference.component.ts +0 -59
- package/src/lib/widget-library/button.component.ts +0 -54
- package/src/lib/widget-library/checkbox.component.ts +0 -74
- package/src/lib/widget-library/checkboxes.component.ts +0 -104
- package/src/lib/widget-library/file.component.ts +0 -36
- package/src/lib/widget-library/hidden.component.ts +0 -39
- package/src/lib/widget-library/input.component.ts +0 -76
- package/src/lib/widget-library/message.component.ts +0 -29
- package/src/lib/widget-library/none.component.ts +0 -12
- package/src/lib/widget-library/number.component.ts +0 -79
- package/src/lib/widget-library/one-of.component.ts +0 -36
- package/src/lib/widget-library/orderable.directive.ts +0 -130
- package/src/lib/widget-library/radios.component.ts +0 -101
- package/src/lib/widget-library/root.component.ts +0 -78
- package/src/lib/widget-library/section.component.ts +0 -133
- package/src/lib/widget-library/select-framework.component.ts +0 -50
- package/src/lib/widget-library/select-widget.component.ts +0 -46
- package/src/lib/widget-library/select.component.ts +0 -96
- package/src/lib/widget-library/submit.component.ts +0 -68
- package/src/lib/widget-library/tab.component.ts +0 -29
- package/src/lib/widget-library/tabs.component.ts +0 -83
- package/src/lib/widget-library/template.component.ts +0 -52
- package/src/lib/widget-library/textarea.component.ts +0 -68
- package/src/lib/widget-library/widget-library.module.ts +0 -13
- package/src/lib/widget-library/widget-library.service.ts +0 -234
- package/src/test.ts +0 -18
- package/tsconfig.lib.json +0 -25
- package/tsconfig.lib.prod.json +0 -9
- package/tsconfig.spec.json +0 -17
- package/tslint.json +0 -11
|
@@ -1,1233 +0,0 @@
|
|
|
1
|
-
import cloneDeep from 'lodash/cloneDeep';
|
|
2
|
-
import _isArray from 'lodash/isArray';
|
|
3
|
-
import _isPlainObject from 'lodash/isPlainObject';
|
|
4
|
-
import uniqueId from 'lodash/uniqueId';
|
|
5
|
-
import { TitleMapItem } from '../json-schema-form.service';
|
|
6
|
-
import {
|
|
7
|
-
checkInlineType,
|
|
8
|
-
getFromSchema,
|
|
9
|
-
getInputType,
|
|
10
|
-
isInputRequired,
|
|
11
|
-
removeRecursiveReferences,
|
|
12
|
-
updateInputOptions
|
|
13
|
-
} from './json-schema.functions';
|
|
14
|
-
import { JsonPointer } from './jsonpointer.functions';
|
|
15
|
-
import {
|
|
16
|
-
copy,
|
|
17
|
-
fixTitle,
|
|
18
|
-
forEach,
|
|
19
|
-
hasOwn
|
|
20
|
-
} from './utility.functions';
|
|
21
|
-
import {
|
|
22
|
-
inArray,
|
|
23
|
-
isArray,
|
|
24
|
-
isDefined,
|
|
25
|
-
isEmpty,
|
|
26
|
-
isNumber,
|
|
27
|
-
isObject,
|
|
28
|
-
isString
|
|
29
|
-
} from './validator.functions';
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Layout function library:
|
|
36
|
-
*
|
|
37
|
-
* buildLayout: Builds a complete layout from an input layout and schema
|
|
38
|
-
*
|
|
39
|
-
* buildLayoutFromSchema: Builds a complete layout entirely from an input schema
|
|
40
|
-
*
|
|
41
|
-
* mapLayout:
|
|
42
|
-
*
|
|
43
|
-
* getLayoutNode:
|
|
44
|
-
*
|
|
45
|
-
* buildTitleMap:
|
|
46
|
-
*/
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* 'buildLayout' function
|
|
50
|
-
*
|
|
51
|
-
* // jsf
|
|
52
|
-
* // widgetLibrary
|
|
53
|
-
* //
|
|
54
|
-
*/
|
|
55
|
-
export function buildLayout_original(jsf, widgetLibrary) {
|
|
56
|
-
let hasSubmitButton = !JsonPointer.get(jsf, '/formOptions/addSubmit');
|
|
57
|
-
const formLayout = mapLayout(jsf.layout, (layoutItem, index, layoutPointer) => {
|
|
58
|
-
const newNode: any = {
|
|
59
|
-
_id: uniqueId(),
|
|
60
|
-
options: {},
|
|
61
|
-
};
|
|
62
|
-
if (isObject(layoutItem)) {
|
|
63
|
-
Object.assign(newNode, layoutItem);
|
|
64
|
-
Object.keys(newNode)
|
|
65
|
-
.filter(option => !inArray(option, [
|
|
66
|
-
'_id', '$ref', 'arrayItem', 'arrayItemType', 'dataPointer', 'dataType',
|
|
67
|
-
'items', 'key', 'name', 'options', 'recursiveReference', 'type', 'widget'
|
|
68
|
-
]))
|
|
69
|
-
.forEach(option => {
|
|
70
|
-
newNode.options[option] = newNode[option];
|
|
71
|
-
delete newNode[option];
|
|
72
|
-
});
|
|
73
|
-
if (!hasOwn(newNode, 'type') && isString(newNode.widget)) {
|
|
74
|
-
newNode.type = newNode.widget;
|
|
75
|
-
delete newNode.widget;
|
|
76
|
-
}
|
|
77
|
-
if (!hasOwn(newNode.options, 'title')) {
|
|
78
|
-
if (hasOwn(newNode.options, 'legend')) {
|
|
79
|
-
newNode.options.title = newNode.options.legend;
|
|
80
|
-
delete newNode.options.legend;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
if (!hasOwn(newNode.options, 'validationMessages')) {
|
|
84
|
-
if (hasOwn(newNode.options, 'errorMessages')) {
|
|
85
|
-
newNode.options.validationMessages = newNode.options.errorMessages;
|
|
86
|
-
delete newNode.options.errorMessages;
|
|
87
|
-
|
|
88
|
-
// Convert Angular Schema Form (AngularJS) 'validationMessage' to
|
|
89
|
-
// Angular JSON Schema Form 'validationMessages'
|
|
90
|
-
// TV4 codes from https://github.com/geraintluff/tv4/blob/master/source/api.js
|
|
91
|
-
} else if (hasOwn(newNode.options, 'validationMessage')) {
|
|
92
|
-
if (typeof newNode.options.validationMessage === 'string') {
|
|
93
|
-
newNode.options.validationMessages = newNode.options.validationMessage;
|
|
94
|
-
} else {
|
|
95
|
-
newNode.options.validationMessages = {};
|
|
96
|
-
Object.keys(newNode.options.validationMessage).forEach(key => {
|
|
97
|
-
const code = key + '';
|
|
98
|
-
const newKey =
|
|
99
|
-
code === '0' ? 'type' :
|
|
100
|
-
code === '1' ? 'enum' :
|
|
101
|
-
code === '100' ? 'multipleOf' :
|
|
102
|
-
code === '101' ? 'minimum' :
|
|
103
|
-
code === '102' ? 'exclusiveMinimum' :
|
|
104
|
-
code === '103' ? 'maximum' :
|
|
105
|
-
code === '104' ? 'exclusiveMaximum' :
|
|
106
|
-
code === '200' ? 'minLength' :
|
|
107
|
-
code === '201' ? 'maxLength' :
|
|
108
|
-
code === '202' ? 'pattern' :
|
|
109
|
-
code === '300' ? 'minProperties' :
|
|
110
|
-
code === '301' ? 'maxProperties' :
|
|
111
|
-
code === '302' ? 'required' :
|
|
112
|
-
code === '304' ? 'dependencies' :
|
|
113
|
-
code === '400' ? 'minItems' :
|
|
114
|
-
code === '401' ? 'maxItems' :
|
|
115
|
-
code === '402' ? 'uniqueItems' :
|
|
116
|
-
code === '500' ? 'format' : code + '';
|
|
117
|
-
newNode.options.validationMessages[newKey] = newNode.options.validationMessage[key];
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
delete newNode.options.validationMessage;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
} else if (JsonPointer.isJsonPointer(layoutItem)) {
|
|
124
|
-
newNode.dataPointer = layoutItem;
|
|
125
|
-
} else if (isString(layoutItem)) {
|
|
126
|
-
newNode.key = layoutItem;
|
|
127
|
-
} else {
|
|
128
|
-
console.error('buildLayout error: Form layout element not recognized:');
|
|
129
|
-
console.error(layoutItem);
|
|
130
|
-
return null;
|
|
131
|
-
}
|
|
132
|
-
let nodeSchema: any = null;
|
|
133
|
-
|
|
134
|
-
// If newNode does not have a dataPointer, try to find an equivalent
|
|
135
|
-
if (!hasOwn(newNode, 'dataPointer')) {
|
|
136
|
-
|
|
137
|
-
// If newNode has a key, change it to a dataPointer
|
|
138
|
-
if (hasOwn(newNode, 'key')) {
|
|
139
|
-
newNode.dataPointer = newNode.key === '*' ? newNode.key :
|
|
140
|
-
JsonPointer.compile(JsonPointer.parseObjectPath(newNode.key), '-');
|
|
141
|
-
delete newNode.key;
|
|
142
|
-
|
|
143
|
-
// If newNode is an array, search for dataPointer in child nodes
|
|
144
|
-
} else if (hasOwn(newNode, 'type') && newNode.type.slice(-5) === 'array') {
|
|
145
|
-
const findDataPointer = (items) => {
|
|
146
|
-
if (items === null || typeof items !== 'object') { return; }
|
|
147
|
-
if (hasOwn(items, 'dataPointer')) { return items.dataPointer; }
|
|
148
|
-
if (isArray(items.items)) {
|
|
149
|
-
for (const item of items.items) {
|
|
150
|
-
if (hasOwn(item, 'dataPointer') && item.dataPointer.indexOf('/-') !== -1) {
|
|
151
|
-
return item.dataPointer;
|
|
152
|
-
}
|
|
153
|
-
if (hasOwn(item, 'items')) {
|
|
154
|
-
const searchItem = findDataPointer(item);
|
|
155
|
-
if (searchItem) { return searchItem; }
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
};
|
|
160
|
-
const childDataPointer = findDataPointer(newNode);
|
|
161
|
-
if (childDataPointer) {
|
|
162
|
-
newNode.dataPointer =
|
|
163
|
-
childDataPointer.slice(0, childDataPointer.lastIndexOf('/-'));
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
if (hasOwn(newNode, 'dataPointer')) {
|
|
169
|
-
if (newNode.dataPointer === '*') {
|
|
170
|
-
return buildLayoutFromSchema(jsf, widgetLibrary, jsf.formValues);
|
|
171
|
-
}
|
|
172
|
-
const nodeValue =
|
|
173
|
-
JsonPointer.get(jsf.formValues, newNode.dataPointer.replace(/\/-/g, '/1'));
|
|
174
|
-
|
|
175
|
-
// TODO: Create function getFormValues(jsf, dataPointer, forRefLibrary)
|
|
176
|
-
// check formOptions.setSchemaDefaults and formOptions.setLayoutDefaults
|
|
177
|
-
// then set apropriate values from initialVaues, schema, or layout
|
|
178
|
-
|
|
179
|
-
newNode.dataPointer =
|
|
180
|
-
JsonPointer.toGenericPointer(newNode.dataPointer, jsf.arrayMap);
|
|
181
|
-
const LastKey = JsonPointer.toKey(newNode.dataPointer);
|
|
182
|
-
if (!newNode.name && isString(LastKey) && LastKey !== '-') {
|
|
183
|
-
newNode.name = LastKey;
|
|
184
|
-
}
|
|
185
|
-
const shortDataPointer = removeRecursiveReferences(
|
|
186
|
-
newNode.dataPointer, jsf.dataRecursiveRefMap, jsf.arrayMap
|
|
187
|
-
);
|
|
188
|
-
const recursive = !shortDataPointer.length ||
|
|
189
|
-
shortDataPointer !== newNode.dataPointer;
|
|
190
|
-
let schemaPointer: string;
|
|
191
|
-
if (!jsf.dataMap.has(shortDataPointer)) {
|
|
192
|
-
jsf.dataMap.set(shortDataPointer, new Map());
|
|
193
|
-
}
|
|
194
|
-
const nodeDataMap = jsf.dataMap.get(shortDataPointer);
|
|
195
|
-
if (nodeDataMap.has('schemaPointer')) {
|
|
196
|
-
schemaPointer = nodeDataMap.get('schemaPointer');
|
|
197
|
-
} else {
|
|
198
|
-
schemaPointer = JsonPointer.toSchemaPointer(shortDataPointer, jsf.schema);
|
|
199
|
-
nodeDataMap.set('schemaPointer', schemaPointer);
|
|
200
|
-
}
|
|
201
|
-
nodeDataMap.set('disabled', !!newNode.options.disabled);
|
|
202
|
-
nodeSchema = JsonPointer.get(jsf.schema, schemaPointer);
|
|
203
|
-
if (nodeSchema) {
|
|
204
|
-
if (!hasOwn(newNode, 'type')) {
|
|
205
|
-
newNode.type = getInputType(nodeSchema, newNode);
|
|
206
|
-
} else if (!widgetLibrary.hasWidget(newNode.type)) {
|
|
207
|
-
const oldWidgetType = newNode.type;
|
|
208
|
-
newNode.type = getInputType(nodeSchema, newNode);
|
|
209
|
-
console.error(`error: widget type "${oldWidgetType}" ` +
|
|
210
|
-
`not found in library. Replacing with "${newNode.type}".`);
|
|
211
|
-
} else {
|
|
212
|
-
newNode.type = checkInlineType(newNode.type, nodeSchema, newNode);
|
|
213
|
-
}
|
|
214
|
-
if (nodeSchema.type === 'object' && isArray(nodeSchema.required)) {
|
|
215
|
-
nodeDataMap.set('required', nodeSchema.required);
|
|
216
|
-
}
|
|
217
|
-
newNode.dataType =
|
|
218
|
-
nodeSchema.type || (hasOwn(nodeSchema, '$ref') ? '$ref' : null);
|
|
219
|
-
updateInputOptions(newNode, nodeSchema, jsf);
|
|
220
|
-
|
|
221
|
-
// Present checkboxes as single control, rather than array
|
|
222
|
-
if (newNode.type === 'checkboxes' && hasOwn(nodeSchema, 'items')) {
|
|
223
|
-
updateInputOptions(newNode, nodeSchema.items, jsf);
|
|
224
|
-
} else if (newNode.dataType === 'array') {
|
|
225
|
-
newNode.options.maxItems = Math.min(
|
|
226
|
-
nodeSchema.maxItems || 1000, newNode.options.maxItems || 1000
|
|
227
|
-
);
|
|
228
|
-
newNode.options.minItems = Math.max(
|
|
229
|
-
nodeSchema.minItems || 0, newNode.options.minItems || 0
|
|
230
|
-
);
|
|
231
|
-
newNode.options.listItems = Math.max(
|
|
232
|
-
newNode.options.listItems || 0, isArray(nodeValue) ? nodeValue.length : 0
|
|
233
|
-
);
|
|
234
|
-
newNode.options.tupleItems =
|
|
235
|
-
isArray(nodeSchema.items) ? nodeSchema.items.length : 0;
|
|
236
|
-
if (newNode.options.maxItems < newNode.options.tupleItems) {
|
|
237
|
-
newNode.options.tupleItems = newNode.options.maxItems;
|
|
238
|
-
newNode.options.listItems = 0;
|
|
239
|
-
} else if (newNode.options.maxItems <
|
|
240
|
-
newNode.options.tupleItems + newNode.options.listItems
|
|
241
|
-
) {
|
|
242
|
-
newNode.options.listItems =
|
|
243
|
-
newNode.options.maxItems - newNode.options.tupleItems;
|
|
244
|
-
} else if (newNode.options.minItems >
|
|
245
|
-
newNode.options.tupleItems + newNode.options.listItems
|
|
246
|
-
) {
|
|
247
|
-
newNode.options.listItems =
|
|
248
|
-
newNode.options.minItems - newNode.options.tupleItems;
|
|
249
|
-
}
|
|
250
|
-
if (!nodeDataMap.has('maxItems')) {
|
|
251
|
-
nodeDataMap.set('maxItems', newNode.options.maxItems);
|
|
252
|
-
nodeDataMap.set('minItems', newNode.options.minItems);
|
|
253
|
-
nodeDataMap.set('tupleItems', newNode.options.tupleItems);
|
|
254
|
-
nodeDataMap.set('listItems', newNode.options.listItems);
|
|
255
|
-
}
|
|
256
|
-
if (!jsf.arrayMap.has(shortDataPointer)) {
|
|
257
|
-
jsf.arrayMap.set(shortDataPointer, newNode.options.tupleItems);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
if (isInputRequired(jsf.schema, schemaPointer)) {
|
|
261
|
-
newNode.options.required = true;
|
|
262
|
-
jsf.fieldsRequired = true;
|
|
263
|
-
}
|
|
264
|
-
} else {
|
|
265
|
-
// TODO: create item in FormGroup model from layout key (?)
|
|
266
|
-
updateInputOptions(newNode, {}, jsf);
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
if (!newNode.options.title && !/^\d+$/.test(newNode.name)) {
|
|
270
|
-
newNode.options.title = fixTitle(newNode.name);
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
if (hasOwn(newNode.options, 'copyValueTo')) {
|
|
274
|
-
if (typeof newNode.options.copyValueTo === 'string') {
|
|
275
|
-
newNode.options.copyValueTo = [newNode.options.copyValueTo];
|
|
276
|
-
}
|
|
277
|
-
if (isArray(newNode.options.copyValueTo)) {
|
|
278
|
-
newNode.options.copyValueTo = newNode.options.copyValueTo.map(item =>
|
|
279
|
-
JsonPointer.compile(JsonPointer.parseObjectPath(item), '-')
|
|
280
|
-
);
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
newNode.widget = widgetLibrary.getWidget(newNode.type);
|
|
285
|
-
nodeDataMap.set('inputType', newNode.type);
|
|
286
|
-
nodeDataMap.set('widget', newNode.widget);
|
|
287
|
-
|
|
288
|
-
if (newNode.dataType === 'array' &&
|
|
289
|
-
(hasOwn(newNode, 'items') || hasOwn(newNode, 'additionalItems'))
|
|
290
|
-
) {
|
|
291
|
-
const itemRefPointer = removeRecursiveReferences(
|
|
292
|
-
newNode.dataPointer + '/-', jsf.dataRecursiveRefMap, jsf.arrayMap
|
|
293
|
-
);
|
|
294
|
-
if (!jsf.dataMap.has(itemRefPointer)) {
|
|
295
|
-
jsf.dataMap.set(itemRefPointer, new Map());
|
|
296
|
-
}
|
|
297
|
-
jsf.dataMap.get(itemRefPointer).set('inputType', 'section');
|
|
298
|
-
|
|
299
|
-
// Fix insufficiently nested array item groups
|
|
300
|
-
if (newNode.items.length > 1) {
|
|
301
|
-
const arrayItemGroup = [];
|
|
302
|
-
for (let i = newNode.items.length - 1; i >= 0; i--) {
|
|
303
|
-
const subItem = newNode.items[i];
|
|
304
|
-
if (hasOwn(subItem, 'dataPointer') &&
|
|
305
|
-
subItem.dataPointer.slice(0, itemRefPointer.length) === itemRefPointer
|
|
306
|
-
) {
|
|
307
|
-
const arrayItem = newNode.items.splice(i, 1)[0];
|
|
308
|
-
arrayItem.dataPointer = newNode.dataPointer + '/-' +
|
|
309
|
-
arrayItem.dataPointer.slice(itemRefPointer.length);
|
|
310
|
-
arrayItemGroup.unshift(arrayItem);
|
|
311
|
-
} else {
|
|
312
|
-
subItem.arrayItem = true;
|
|
313
|
-
// TODO: Check schema to get arrayItemType and removable
|
|
314
|
-
subItem.arrayItemType = 'list';
|
|
315
|
-
subItem.removable = newNode.options.removable !== false;
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
if (arrayItemGroup.length) {
|
|
319
|
-
newNode.items.push({
|
|
320
|
-
_id: uniqueId(),
|
|
321
|
-
arrayItem: true,
|
|
322
|
-
arrayItemType: newNode.options.tupleItems > newNode.items.length ?
|
|
323
|
-
'tuple' : 'list',
|
|
324
|
-
items: arrayItemGroup,
|
|
325
|
-
options: { removable: newNode.options.removable !== false, },
|
|
326
|
-
dataPointer: newNode.dataPointer + '/-',
|
|
327
|
-
type: 'section',
|
|
328
|
-
widget: widgetLibrary.getWidget('section'),
|
|
329
|
-
});
|
|
330
|
-
}
|
|
331
|
-
} else {
|
|
332
|
-
// TODO: Fix to hndle multiple items
|
|
333
|
-
newNode.items[0].arrayItem = true;
|
|
334
|
-
if (!newNode.items[0].dataPointer) {
|
|
335
|
-
newNode.items[0].dataPointer =
|
|
336
|
-
JsonPointer.toGenericPointer(itemRefPointer, jsf.arrayMap);
|
|
337
|
-
}
|
|
338
|
-
if (!JsonPointer.has(newNode, '/items/0/options/removable')) {
|
|
339
|
-
newNode.items[0].options.removable = true;
|
|
340
|
-
}
|
|
341
|
-
if (newNode.options.orderable === false) {
|
|
342
|
-
newNode.items[0].options.orderable = false;
|
|
343
|
-
}
|
|
344
|
-
newNode.items[0].arrayItemType =
|
|
345
|
-
newNode.options.tupleItems ? 'tuple' : 'list';
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
if (isArray(newNode.items)) {
|
|
349
|
-
const arrayListItems =
|
|
350
|
-
newNode.items.filter(item => item.type !== '$ref').length -
|
|
351
|
-
newNode.options.tupleItems;
|
|
352
|
-
if (arrayListItems > newNode.options.listItems) {
|
|
353
|
-
newNode.options.listItems = arrayListItems;
|
|
354
|
-
nodeDataMap.set('listItems', arrayListItems);
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
if (!hasOwn(jsf.layoutRefLibrary, itemRefPointer)) {
|
|
359
|
-
jsf.layoutRefLibrary[itemRefPointer] =
|
|
360
|
-
cloneDeep(newNode.items[newNode.items.length - 1]);
|
|
361
|
-
if (recursive) {
|
|
362
|
-
jsf.layoutRefLibrary[itemRefPointer].recursiveReference = true;
|
|
363
|
-
}
|
|
364
|
-
forEach(jsf.layoutRefLibrary[itemRefPointer], (item, key) => {
|
|
365
|
-
if (hasOwn(item, '_id')) { item._id = null; }
|
|
366
|
-
if (recursive) {
|
|
367
|
-
if (hasOwn(item, 'dataPointer')) {
|
|
368
|
-
item.dataPointer = item.dataPointer.slice(itemRefPointer.length);
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
}, 'top-down');
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
// Add any additional default items
|
|
375
|
-
if (!newNode.recursiveReference || newNode.options.required) {
|
|
376
|
-
const arrayLength = Math.min(Math.max(
|
|
377
|
-
newNode.options.tupleItems + newNode.options.listItems,
|
|
378
|
-
isArray(nodeValue) ? nodeValue.length : 0
|
|
379
|
-
), newNode.options.maxItems);
|
|
380
|
-
for (let i = newNode.items.length; i < arrayLength; i++) {
|
|
381
|
-
newNode.items.push(getLayoutNode({
|
|
382
|
-
$ref: itemRefPointer,
|
|
383
|
-
dataPointer: newNode.dataPointer,
|
|
384
|
-
recursiveReference: newNode.recursiveReference,
|
|
385
|
-
}, jsf, widgetLibrary));
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
// If needed, add button to add items to array
|
|
390
|
-
if (newNode.options.addable !== false &&
|
|
391
|
-
newNode.options.minItems < newNode.options.maxItems &&
|
|
392
|
-
(newNode.items[newNode.items.length - 1] || {}).type !== '$ref'
|
|
393
|
-
) {
|
|
394
|
-
let buttonText = 'Add';
|
|
395
|
-
if (newNode.options.title) {
|
|
396
|
-
if (/^add\b/i.test(newNode.options.title)) {
|
|
397
|
-
buttonText = newNode.options.title;
|
|
398
|
-
} else {
|
|
399
|
-
buttonText += ' ' + newNode.options.title;
|
|
400
|
-
}
|
|
401
|
-
} else if (newNode.name && !/^\d+$/.test(newNode.name)) {
|
|
402
|
-
if (/^add\b/i.test(newNode.name)) {
|
|
403
|
-
buttonText += ' ' + fixTitle(newNode.name);
|
|
404
|
-
} else {
|
|
405
|
-
buttonText = fixTitle(newNode.name);
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
// If newNode doesn't have a title, look for title of parent array item
|
|
409
|
-
} else {
|
|
410
|
-
const parentSchema =
|
|
411
|
-
getFromSchema(jsf.schema, newNode.dataPointer, 'parentSchema');
|
|
412
|
-
if (hasOwn(parentSchema, 'title')) {
|
|
413
|
-
buttonText += ' to ' + parentSchema.title;
|
|
414
|
-
} else {
|
|
415
|
-
const pointerArray = JsonPointer.parse(newNode.dataPointer);
|
|
416
|
-
buttonText += ' to ' + fixTitle(pointerArray[pointerArray.length - 2]);
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
newNode.items.push({
|
|
420
|
-
_id: uniqueId(),
|
|
421
|
-
arrayItem: true,
|
|
422
|
-
arrayItemType: 'list',
|
|
423
|
-
dataPointer: newNode.dataPointer + '/-',
|
|
424
|
-
options: {
|
|
425
|
-
listItems: newNode.options.listItems,
|
|
426
|
-
maxItems: newNode.options.maxItems,
|
|
427
|
-
minItems: newNode.options.minItems,
|
|
428
|
-
removable: false,
|
|
429
|
-
title: buttonText,
|
|
430
|
-
tupleItems: newNode.options.tupleItems,
|
|
431
|
-
},
|
|
432
|
-
recursiveReference: recursive,
|
|
433
|
-
type: '$ref',
|
|
434
|
-
widget: widgetLibrary.getWidget('$ref'),
|
|
435
|
-
$ref: itemRefPointer,
|
|
436
|
-
});
|
|
437
|
-
if (isString(JsonPointer.get(newNode, '/style/add'))) {
|
|
438
|
-
newNode.items[newNode.items.length - 1].options.fieldStyle =
|
|
439
|
-
newNode.style.add;
|
|
440
|
-
delete newNode.style.add;
|
|
441
|
-
if (isEmpty(newNode.style)) { delete newNode.style; }
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
} else {
|
|
445
|
-
newNode.arrayItem = false;
|
|
446
|
-
}
|
|
447
|
-
} else if (hasOwn(newNode, 'type') || hasOwn(newNode, 'items')) {
|
|
448
|
-
const parentType: string =
|
|
449
|
-
JsonPointer.get(jsf.layout, layoutPointer, 0, -2).type;
|
|
450
|
-
if (!hasOwn(newNode, 'type')) {
|
|
451
|
-
newNode.type =
|
|
452
|
-
inArray(parentType, ['tabs', 'tabarray']) ? 'tab' : 'array';
|
|
453
|
-
}
|
|
454
|
-
newNode.arrayItem = parentType === 'array';
|
|
455
|
-
newNode.widget = widgetLibrary.getWidget(newNode.type);
|
|
456
|
-
updateInputOptions(newNode, {}, jsf);
|
|
457
|
-
}
|
|
458
|
-
if (newNode.type === 'submit') { hasSubmitButton = true; }
|
|
459
|
-
return newNode;
|
|
460
|
-
});
|
|
461
|
-
if (jsf.hasRootReference) {
|
|
462
|
-
const fullLayout = cloneDeep(formLayout);
|
|
463
|
-
if (fullLayout[fullLayout.length - 1].type === 'submit') { fullLayout.pop(); }
|
|
464
|
-
jsf.layoutRefLibrary[''] = {
|
|
465
|
-
_id: null,
|
|
466
|
-
dataPointer: '',
|
|
467
|
-
dataType: 'object',
|
|
468
|
-
items: fullLayout,
|
|
469
|
-
name: '',
|
|
470
|
-
options: cloneDeep(jsf.formOptions.defaultWidgetOptions),
|
|
471
|
-
recursiveReference: true,
|
|
472
|
-
required: false,
|
|
473
|
-
type: 'section',
|
|
474
|
-
widget: widgetLibrary.getWidget('section'),
|
|
475
|
-
};
|
|
476
|
-
}
|
|
477
|
-
if (!hasSubmitButton) {
|
|
478
|
-
formLayout.push({
|
|
479
|
-
_id: uniqueId(),
|
|
480
|
-
options: { title: 'Submit' },
|
|
481
|
-
type: 'submit',
|
|
482
|
-
widget: widgetLibrary.getWidget('submit'),
|
|
483
|
-
});
|
|
484
|
-
}
|
|
485
|
-
return formLayout;
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
//TODO-review:this implements a quick 'post' fix rather than an
|
|
489
|
-
//integrared ideal fix
|
|
490
|
-
export function buildLayout(jsf, widgetLibrary) {
|
|
491
|
-
let layout=buildLayout_original(jsf, widgetLibrary);
|
|
492
|
-
if (jsf.formValues) {
|
|
493
|
-
let fixedLayout = fixNestedArrayLayout({
|
|
494
|
-
builtLayout: layout,
|
|
495
|
-
formData: jsf.formValues
|
|
496
|
-
});
|
|
497
|
-
}
|
|
498
|
-
return layout;
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
function fixNestedArrayLayout(options: any) {
|
|
504
|
-
let { builtLayout, formData } = options;
|
|
505
|
-
let arrLengths = {};
|
|
506
|
-
let traverseObj = function (obj, path, onValue?) {
|
|
507
|
-
if (_isArray(obj)) {
|
|
508
|
-
onValue && onValue(obj, path);
|
|
509
|
-
obj.forEach((item, ind) => {
|
|
510
|
-
onValue && onValue(item, path + "/" + ind);
|
|
511
|
-
traverseObj(item, path + "/" + ind, onValue);
|
|
512
|
-
});
|
|
513
|
-
return;
|
|
514
|
-
}
|
|
515
|
-
if (_isPlainObject(obj)) {
|
|
516
|
-
onValue && onValue(obj, path);
|
|
517
|
-
Object.keys(obj).forEach(key => {
|
|
518
|
-
onValue && onValue(obj[key], path + "/" + key);
|
|
519
|
-
traverseObj(obj[key], path + "/" + key, onValue);
|
|
520
|
-
});
|
|
521
|
-
return
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
traverseObj(formData, "", (value, path) => {
|
|
525
|
-
if (_isArray(value)) {
|
|
526
|
-
arrLengths[path] = arrLengths[path] || value.length;
|
|
527
|
-
}
|
|
528
|
-
});
|
|
529
|
-
|
|
530
|
-
let getDataSize = (options: any) => {
|
|
531
|
-
let { data, dataPointer, indexArray } = options;
|
|
532
|
-
let dashCount = 0;
|
|
533
|
-
let dpInstance = dataPointer.substring(1).split("/").map((part, pind) => {
|
|
534
|
-
if (part == "-" && indexArray[dashCount] != undefined) {
|
|
535
|
-
return indexArray[dashCount++];
|
|
536
|
-
}
|
|
537
|
-
return part;
|
|
538
|
-
})
|
|
539
|
-
.join("/");
|
|
540
|
-
dpInstance = "/" + dpInstance;
|
|
541
|
-
let arrSize = arrLengths[dpInstance];
|
|
542
|
-
return arrSize;
|
|
543
|
-
}
|
|
544
|
-
//still too buggy
|
|
545
|
-
let createNonRefItem = (nodeWithRef: any) => {
|
|
546
|
-
let templateNode = {
|
|
547
|
-
"type": "section", //check this could also be array?
|
|
548
|
-
"recursiveReference": false,//check this
|
|
549
|
-
"items": []
|
|
550
|
-
}
|
|
551
|
-
let clone = cloneDeep(nodeWithRef);
|
|
552
|
-
//commented out for now so that it behaves as ususal
|
|
553
|
-
//_.merge(clone,templateNode);
|
|
554
|
-
return clone;
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
let rebuildLayout = (options: any) => {
|
|
558
|
-
let { builtLayout, indices, parentDataPointer, indexPos } = options;
|
|
559
|
-
indices = indices || [];
|
|
560
|
-
indexPos = indexPos == undefined ? indexPos = -1 : indexPos;
|
|
561
|
-
if (_isArray(builtLayout)) {
|
|
562
|
-
builtLayout.forEach((item, index) => {
|
|
563
|
-
rebuildLayout({
|
|
564
|
-
builtLayout: item,
|
|
565
|
-
indices: indices,
|
|
566
|
-
indexPos: indexPos,
|
|
567
|
-
parentDataPointer: builtLayout.dataPointer || parentDataPointer
|
|
568
|
-
})
|
|
569
|
-
})
|
|
570
|
-
return;
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
let dataTypes=["array"];//check only array for now
|
|
574
|
-
//for now added condition to ignore recursive references
|
|
575
|
-
if (builtLayout.items && dataTypes.indexOf(builtLayout.dataType)>=0
|
|
576
|
-
&& builtLayout.dataPointer
|
|
577
|
-
&& !builtLayout.recursiveReference
|
|
578
|
-
) {
|
|
579
|
-
let numDataItems: any = getDataSize({
|
|
580
|
-
data: formData,
|
|
581
|
-
dataPointer: builtLayout.dataPointer,
|
|
582
|
-
indexArray: indices
|
|
583
|
-
});
|
|
584
|
-
let numActualItems = builtLayout.items.length;
|
|
585
|
-
//check if there's ref items, if so ignore it and therefore
|
|
586
|
-
//decrement the item count
|
|
587
|
-
builtLayout.items.forEach(item => {
|
|
588
|
-
if (item.type && item.type == "$ref") {
|
|
589
|
-
numActualItems--;
|
|
590
|
-
}
|
|
591
|
-
});
|
|
592
|
-
numActualItems = Math.max(numActualItems, 0);//avoid dealing with negatives
|
|
593
|
-
if (numActualItems < numDataItems) {
|
|
594
|
-
|
|
595
|
-
let numItemsNeeded = numDataItems - numActualItems;
|
|
596
|
-
//added to ignore recursive references
|
|
597
|
-
if (numActualItems == 0 && builtLayout.items[0].recursiveReference) {
|
|
598
|
-
numItemsNeeded = 0
|
|
599
|
-
}
|
|
600
|
-
for (let i = 0; i < numItemsNeeded; i++) {
|
|
601
|
-
//node must not be of type "type": "$ref"
|
|
602
|
-
//if it is then manufacture our own
|
|
603
|
-
let isRefNode = builtLayout.items[0].type && builtLayout.items[0].type == "$ref";
|
|
604
|
-
let newItem = isRefNode
|
|
605
|
-
? createNonRefItem(builtLayout.items[0])
|
|
606
|
-
: cloneDeep(builtLayout.items[0]);//copy first
|
|
607
|
-
newItem._id = uniqueId("new_");
|
|
608
|
-
builtLayout.items.unshift(newItem);
|
|
609
|
-
}
|
|
610
|
-
if (builtLayout.options.listItems) {
|
|
611
|
-
builtLayout.options.listItems = numDataItems;
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
indices[builtLayout.dataPointer] = indices[builtLayout.dataPointer] || -1;
|
|
615
|
-
indexPos++;
|
|
616
|
-
builtLayout.items.forEach((item, index) => {
|
|
617
|
-
indices[indexPos] = index
|
|
618
|
-
rebuildLayout({
|
|
619
|
-
builtLayout: item,
|
|
620
|
-
indices: indices,
|
|
621
|
-
parentDataPointer: builtLayout.dataPointer,
|
|
622
|
-
indexPos: indexPos
|
|
623
|
-
})
|
|
624
|
-
})
|
|
625
|
-
indexPos--;
|
|
626
|
-
} else {
|
|
627
|
-
if (builtLayout.items) {
|
|
628
|
-
builtLayout.items.forEach((item, index) => {
|
|
629
|
-
rebuildLayout({
|
|
630
|
-
builtLayout: item,
|
|
631
|
-
indices: indices,
|
|
632
|
-
parentDataPointer: parentDataPointer,
|
|
633
|
-
indexPos: indexPos
|
|
634
|
-
})
|
|
635
|
-
})
|
|
636
|
-
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
}
|
|
642
|
-
rebuildLayout({
|
|
643
|
-
builtLayout: builtLayout
|
|
644
|
-
});
|
|
645
|
-
//NB original is mutated
|
|
646
|
-
let fixedLayout = builtLayout;
|
|
647
|
-
return fixedLayout;
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
/**
|
|
651
|
-
* 'buildLayoutFromSchema' function
|
|
652
|
-
*
|
|
653
|
-
* // jsf -
|
|
654
|
-
* // widgetLibrary -
|
|
655
|
-
* // nodeValue -
|
|
656
|
-
* // { string = '' } schemaPointer -
|
|
657
|
-
* // { string = '' } dataPointer -
|
|
658
|
-
* // { boolean = false } arrayItem -
|
|
659
|
-
* // { string = null } arrayItemType -
|
|
660
|
-
* // { boolean = null } removable -
|
|
661
|
-
* // { boolean = false } forRefLibrary -
|
|
662
|
-
* // { string = '' } dataPointerPrefix -
|
|
663
|
-
* //
|
|
664
|
-
*/
|
|
665
|
-
export function buildLayoutFromSchema(
|
|
666
|
-
jsf, widgetLibrary, nodeValue = null, schemaPointer = '',
|
|
667
|
-
dataPointer = '', arrayItem = false, arrayItemType: string = null,
|
|
668
|
-
removable: boolean = null, forRefLibrary = false, dataPointerPrefix = ''
|
|
669
|
-
) {
|
|
670
|
-
const schema = JsonPointer.get(jsf.schema, schemaPointer);
|
|
671
|
-
if (!hasOwn(schema, 'type') && !hasOwn(schema, '$ref') &&
|
|
672
|
-
!hasOwn(schema, 'x-schema-form')
|
|
673
|
-
) { return null; }
|
|
674
|
-
const newNodeType: string = getInputType(schema);
|
|
675
|
-
if (!isDefined(nodeValue) && (
|
|
676
|
-
jsf.formOptions.setSchemaDefaults === true ||
|
|
677
|
-
(jsf.formOptions.setSchemaDefaults === 'auto' && isEmpty(jsf.formValues))
|
|
678
|
-
)) {
|
|
679
|
-
nodeValue = JsonPointer.get(jsf.schema, schemaPointer + '/default');
|
|
680
|
-
}
|
|
681
|
-
let newNode: any = {
|
|
682
|
-
_id: forRefLibrary ? null : uniqueId(),
|
|
683
|
-
arrayItem: arrayItem,
|
|
684
|
-
dataPointer: JsonPointer.toGenericPointer(dataPointer, jsf.arrayMap),
|
|
685
|
-
dataType: schema.type || (hasOwn(schema, '$ref') ? '$ref' : null),
|
|
686
|
-
options: {},
|
|
687
|
-
required: isInputRequired(jsf.schema, schemaPointer),
|
|
688
|
-
type: newNodeType,
|
|
689
|
-
widget: widgetLibrary.getWidget(newNodeType),
|
|
690
|
-
};
|
|
691
|
-
const lastDataKey = JsonPointer.toKey(newNode.dataPointer);
|
|
692
|
-
if (lastDataKey !== '-') { newNode.name = lastDataKey; }
|
|
693
|
-
if (newNode.arrayItem) {
|
|
694
|
-
newNode.arrayItemType = arrayItemType;
|
|
695
|
-
newNode.options.removable = removable !== false;
|
|
696
|
-
}
|
|
697
|
-
const shortDataPointer = removeRecursiveReferences(
|
|
698
|
-
dataPointerPrefix + dataPointer, jsf.dataRecursiveRefMap, jsf.arrayMap
|
|
699
|
-
);
|
|
700
|
-
const recursive = !shortDataPointer.length ||
|
|
701
|
-
shortDataPointer !== dataPointerPrefix + dataPointer;
|
|
702
|
-
if (!jsf.dataMap.has(shortDataPointer)) {
|
|
703
|
-
jsf.dataMap.set(shortDataPointer, new Map());
|
|
704
|
-
}
|
|
705
|
-
const nodeDataMap = jsf.dataMap.get(shortDataPointer);
|
|
706
|
-
if (!nodeDataMap.has('inputType')) {
|
|
707
|
-
nodeDataMap.set('schemaPointer', schemaPointer);
|
|
708
|
-
nodeDataMap.set('inputType', newNode.type);
|
|
709
|
-
nodeDataMap.set('widget', newNode.widget);
|
|
710
|
-
nodeDataMap.set('disabled', !!newNode.options.disabled);
|
|
711
|
-
}
|
|
712
|
-
updateInputOptions(newNode, schema, jsf);
|
|
713
|
-
if (!newNode.options.title && newNode.name && !/^\d+$/.test(newNode.name)) {
|
|
714
|
-
newNode.options.title = fixTitle(newNode.name);
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
if (newNode.dataType === 'object') {
|
|
718
|
-
if (isArray(schema.required) && !nodeDataMap.has('required')) {
|
|
719
|
-
nodeDataMap.set('required', schema.required);
|
|
720
|
-
}
|
|
721
|
-
if (isObject(schema.properties)) {
|
|
722
|
-
const newSection: any[] = [];
|
|
723
|
-
const propertyKeys = schema['ui:order'] || Object.keys(schema.properties);
|
|
724
|
-
if (propertyKeys.includes('*') && !hasOwn(schema.properties, '*')) {
|
|
725
|
-
const unnamedKeys = Object.keys(schema.properties)
|
|
726
|
-
.filter(key => !propertyKeys.includes(key));
|
|
727
|
-
for (let i = propertyKeys.length - 1; i >= 0; i--) {
|
|
728
|
-
if (propertyKeys[i] === '*') {
|
|
729
|
-
propertyKeys.splice(i, 1, ...unnamedKeys);
|
|
730
|
-
}
|
|
731
|
-
}
|
|
732
|
-
}
|
|
733
|
-
propertyKeys
|
|
734
|
-
.filter(key => hasOwn(schema.properties, key) ||
|
|
735
|
-
hasOwn(schema, 'additionalProperties')
|
|
736
|
-
)
|
|
737
|
-
.forEach(key => {
|
|
738
|
-
const keySchemaPointer = hasOwn(schema.properties, key) ?
|
|
739
|
-
'/properties/' + key : '/additionalProperties';
|
|
740
|
-
const innerItem = buildLayoutFromSchema(
|
|
741
|
-
jsf, widgetLibrary, isObject(nodeValue) ? nodeValue[key] : null,
|
|
742
|
-
schemaPointer + keySchemaPointer,
|
|
743
|
-
dataPointer + '/' + key,
|
|
744
|
-
false, null, null, forRefLibrary, dataPointerPrefix
|
|
745
|
-
);
|
|
746
|
-
if (innerItem) {
|
|
747
|
-
if (isInputRequired(schema, '/' + key)) {
|
|
748
|
-
innerItem.options.required = true;
|
|
749
|
-
jsf.fieldsRequired = true;
|
|
750
|
-
}
|
|
751
|
-
newSection.push(innerItem);
|
|
752
|
-
}
|
|
753
|
-
});
|
|
754
|
-
if (dataPointer === '' && !forRefLibrary) {
|
|
755
|
-
newNode = newSection;
|
|
756
|
-
} else {
|
|
757
|
-
newNode.items = newSection;
|
|
758
|
-
}
|
|
759
|
-
}
|
|
760
|
-
// TODO: Add patternProperties and additionalProperties inputs?
|
|
761
|
-
// ... possibly provide a way to enter both key names and values?
|
|
762
|
-
// if (isObject(schema.patternProperties)) { }
|
|
763
|
-
// if (isObject(schema.additionalProperties)) { }
|
|
764
|
-
|
|
765
|
-
} else if (newNode.dataType === 'array') {
|
|
766
|
-
newNode.items = [];
|
|
767
|
-
newNode.options.maxItems = Math.min(
|
|
768
|
-
schema.maxItems || 1000, newNode.options.maxItems || 1000
|
|
769
|
-
);
|
|
770
|
-
newNode.options.minItems = Math.max(
|
|
771
|
-
schema.minItems || 0, newNode.options.minItems || 0
|
|
772
|
-
);
|
|
773
|
-
if (!newNode.options.minItems && isInputRequired(jsf.schema, schemaPointer)) {
|
|
774
|
-
newNode.options.minItems = 1;
|
|
775
|
-
}
|
|
776
|
-
if (!hasOwn(newNode.options, 'listItems')) { newNode.options.listItems = 1; }
|
|
777
|
-
newNode.options.tupleItems = isArray(schema.items) ? schema.items.length : 0;
|
|
778
|
-
if (newNode.options.maxItems <= newNode.options.tupleItems) {
|
|
779
|
-
newNode.options.tupleItems = newNode.options.maxItems;
|
|
780
|
-
newNode.options.listItems = 0;
|
|
781
|
-
} else if (newNode.options.maxItems <
|
|
782
|
-
newNode.options.tupleItems + newNode.options.listItems
|
|
783
|
-
) {
|
|
784
|
-
newNode.options.listItems = newNode.options.maxItems - newNode.options.tupleItems;
|
|
785
|
-
} else if (newNode.options.minItems >
|
|
786
|
-
newNode.options.tupleItems + newNode.options.listItems
|
|
787
|
-
) {
|
|
788
|
-
newNode.options.listItems = newNode.options.minItems - newNode.options.tupleItems;
|
|
789
|
-
}
|
|
790
|
-
if (!nodeDataMap.has('maxItems')) {
|
|
791
|
-
nodeDataMap.set('maxItems', newNode.options.maxItems);
|
|
792
|
-
nodeDataMap.set('minItems', newNode.options.minItems);
|
|
793
|
-
nodeDataMap.set('tupleItems', newNode.options.tupleItems);
|
|
794
|
-
nodeDataMap.set('listItems', newNode.options.listItems);
|
|
795
|
-
}
|
|
796
|
-
if (!jsf.arrayMap.has(shortDataPointer)) {
|
|
797
|
-
jsf.arrayMap.set(shortDataPointer, newNode.options.tupleItems);
|
|
798
|
-
}
|
|
799
|
-
removable = newNode.options.removable !== false;
|
|
800
|
-
let additionalItemsSchemaPointer: string = null;
|
|
801
|
-
|
|
802
|
-
// If 'items' is an array = tuple items
|
|
803
|
-
if (isArray(schema.items)) {
|
|
804
|
-
newNode.items = [];
|
|
805
|
-
for (let i = 0; i < newNode.options.tupleItems; i++) {
|
|
806
|
-
let newItem: any;
|
|
807
|
-
const itemRefPointer = removeRecursiveReferences(
|
|
808
|
-
shortDataPointer + '/' + i, jsf.dataRecursiveRefMap, jsf.arrayMap
|
|
809
|
-
);
|
|
810
|
-
const itemRecursive = !itemRefPointer.length ||
|
|
811
|
-
itemRefPointer !== shortDataPointer + '/' + i;
|
|
812
|
-
|
|
813
|
-
// If removable, add tuple item layout to layoutRefLibrary
|
|
814
|
-
if (removable && i >= newNode.options.minItems) {
|
|
815
|
-
if (!hasOwn(jsf.layoutRefLibrary, itemRefPointer)) {
|
|
816
|
-
// Set to null first to prevent recursive reference from causing endless loop
|
|
817
|
-
jsf.layoutRefLibrary[itemRefPointer] = null;
|
|
818
|
-
jsf.layoutRefLibrary[itemRefPointer] = buildLayoutFromSchema(
|
|
819
|
-
jsf, widgetLibrary, isArray(nodeValue) ? nodeValue[i] : null,
|
|
820
|
-
schemaPointer + '/items/' + i,
|
|
821
|
-
itemRecursive ? '' : dataPointer + '/' + i,
|
|
822
|
-
true, 'tuple', true, true, itemRecursive ? dataPointer + '/' + i : ''
|
|
823
|
-
);
|
|
824
|
-
if (itemRecursive) {
|
|
825
|
-
jsf.layoutRefLibrary[itemRefPointer].recursiveReference = true;
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
newItem = getLayoutNode({
|
|
829
|
-
$ref: itemRefPointer,
|
|
830
|
-
dataPointer: dataPointer + '/' + i,
|
|
831
|
-
recursiveReference: itemRecursive,
|
|
832
|
-
}, jsf, widgetLibrary, isArray(nodeValue) ? nodeValue[i] : null);
|
|
833
|
-
} else {
|
|
834
|
-
newItem = buildLayoutFromSchema(
|
|
835
|
-
jsf, widgetLibrary, isArray(nodeValue) ? nodeValue[i] : null,
|
|
836
|
-
schemaPointer + '/items/' + i,
|
|
837
|
-
dataPointer + '/' + i,
|
|
838
|
-
true, 'tuple', false, forRefLibrary, dataPointerPrefix
|
|
839
|
-
);
|
|
840
|
-
}
|
|
841
|
-
if (newItem) { newNode.items.push(newItem); }
|
|
842
|
-
}
|
|
843
|
-
|
|
844
|
-
// If 'additionalItems' is an object = additional list items, after tuple items
|
|
845
|
-
if (isObject(schema.additionalItems)) {
|
|
846
|
-
additionalItemsSchemaPointer = schemaPointer + '/additionalItems';
|
|
847
|
-
}
|
|
848
|
-
|
|
849
|
-
// If 'items' is an object = list items only (no tuple items)
|
|
850
|
-
} else if (isObject(schema.items)) {
|
|
851
|
-
additionalItemsSchemaPointer = schemaPointer + '/items';
|
|
852
|
-
}
|
|
853
|
-
|
|
854
|
-
if (additionalItemsSchemaPointer) {
|
|
855
|
-
const itemRefPointer = removeRecursiveReferences(
|
|
856
|
-
shortDataPointer + '/-', jsf.dataRecursiveRefMap, jsf.arrayMap
|
|
857
|
-
);
|
|
858
|
-
const itemRecursive = !itemRefPointer.length ||
|
|
859
|
-
itemRefPointer !== shortDataPointer + '/-';
|
|
860
|
-
const itemSchemaPointer = removeRecursiveReferences(
|
|
861
|
-
additionalItemsSchemaPointer, jsf.schemaRecursiveRefMap, jsf.arrayMap
|
|
862
|
-
);
|
|
863
|
-
// Add list item layout to layoutRefLibrary
|
|
864
|
-
if (itemRefPointer.length && !hasOwn(jsf.layoutRefLibrary, itemRefPointer)) {
|
|
865
|
-
// Set to null first to prevent recursive reference from causing endless loop
|
|
866
|
-
jsf.layoutRefLibrary[itemRefPointer] = null;
|
|
867
|
-
jsf.layoutRefLibrary[itemRefPointer] = buildLayoutFromSchema(
|
|
868
|
-
jsf, widgetLibrary, null,
|
|
869
|
-
itemSchemaPointer,
|
|
870
|
-
itemRecursive ? '' : dataPointer + '/-',
|
|
871
|
-
true, 'list', removable, true, itemRecursive ? dataPointer + '/-' : ''
|
|
872
|
-
);
|
|
873
|
-
if (itemRecursive) {
|
|
874
|
-
jsf.layoutRefLibrary[itemRefPointer].recursiveReference = true;
|
|
875
|
-
}
|
|
876
|
-
}
|
|
877
|
-
|
|
878
|
-
// Add any additional default items
|
|
879
|
-
if (!itemRecursive || newNode.options.required) {
|
|
880
|
-
const arrayLength = Math.min(Math.max(
|
|
881
|
-
itemRecursive ? 0 :
|
|
882
|
-
newNode.options.tupleItems + newNode.options.listItems,
|
|
883
|
-
isArray(nodeValue) ? nodeValue.length : 0
|
|
884
|
-
), newNode.options.maxItems);
|
|
885
|
-
if (newNode.items.length < arrayLength) {
|
|
886
|
-
for (let i = newNode.items.length; i < arrayLength; i++) {
|
|
887
|
-
newNode.items.push(getLayoutNode({
|
|
888
|
-
$ref: itemRefPointer,
|
|
889
|
-
dataPointer: dataPointer + '/-',
|
|
890
|
-
recursiveReference: itemRecursive,
|
|
891
|
-
}, jsf, widgetLibrary, isArray(nodeValue) ? nodeValue[i] : null));
|
|
892
|
-
}
|
|
893
|
-
}
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
// If needed, add button to add items to array
|
|
897
|
-
if (newNode.options.addable !== false &&
|
|
898
|
-
newNode.options.minItems < newNode.options.maxItems &&
|
|
899
|
-
(newNode.items[newNode.items.length - 1] || {}).type !== '$ref'
|
|
900
|
-
) {
|
|
901
|
-
let buttonText =
|
|
902
|
-
((jsf.layoutRefLibrary[itemRefPointer] || {}).options || {}).title;
|
|
903
|
-
const prefix = buttonText ? 'Add ' : 'Add to ';
|
|
904
|
-
if (!buttonText) {
|
|
905
|
-
buttonText = schema.title || fixTitle(JsonPointer.toKey(dataPointer));
|
|
906
|
-
}
|
|
907
|
-
if (!/^add\b/i.test(buttonText)) { buttonText = prefix + buttonText; }
|
|
908
|
-
newNode.items.push({
|
|
909
|
-
_id: uniqueId(),
|
|
910
|
-
arrayItem: true,
|
|
911
|
-
arrayItemType: 'list',
|
|
912
|
-
dataPointer: newNode.dataPointer + '/-',
|
|
913
|
-
options: {
|
|
914
|
-
listItems: newNode.options.listItems,
|
|
915
|
-
maxItems: newNode.options.maxItems,
|
|
916
|
-
minItems: newNode.options.minItems,
|
|
917
|
-
removable: false,
|
|
918
|
-
title: buttonText,
|
|
919
|
-
tupleItems: newNode.options.tupleItems,
|
|
920
|
-
},
|
|
921
|
-
recursiveReference: itemRecursive,
|
|
922
|
-
type: '$ref',
|
|
923
|
-
widget: widgetLibrary.getWidget('$ref'),
|
|
924
|
-
$ref: itemRefPointer,
|
|
925
|
-
});
|
|
926
|
-
}
|
|
927
|
-
}
|
|
928
|
-
|
|
929
|
-
} else if (newNode.dataType === '$ref') {
|
|
930
|
-
const schemaRef = JsonPointer.compile(schema.$ref);
|
|
931
|
-
const dataRef = JsonPointer.toDataPointer(schemaRef, jsf.schema);
|
|
932
|
-
let buttonText = '';
|
|
933
|
-
|
|
934
|
-
// Get newNode title
|
|
935
|
-
if (newNode.options.add) {
|
|
936
|
-
buttonText = newNode.options.add;
|
|
937
|
-
} else if (newNode.name && !/^\d+$/.test(newNode.name)) {
|
|
938
|
-
buttonText =
|
|
939
|
-
(/^add\b/i.test(newNode.name) ? '' : 'Add ') + fixTitle(newNode.name);
|
|
940
|
-
|
|
941
|
-
// If newNode doesn't have a title, look for title of parent array item
|
|
942
|
-
} else {
|
|
943
|
-
const parentSchema =
|
|
944
|
-
JsonPointer.get(jsf.schema, schemaPointer, 0, -1);
|
|
945
|
-
if (hasOwn(parentSchema, 'title')) {
|
|
946
|
-
buttonText = 'Add to ' + parentSchema.title;
|
|
947
|
-
} else {
|
|
948
|
-
const pointerArray = JsonPointer.parse(newNode.dataPointer);
|
|
949
|
-
buttonText = 'Add to ' + fixTitle(pointerArray[pointerArray.length - 2]);
|
|
950
|
-
}
|
|
951
|
-
}
|
|
952
|
-
Object.assign(newNode, {
|
|
953
|
-
recursiveReference: true,
|
|
954
|
-
widget: widgetLibrary.getWidget('$ref'),
|
|
955
|
-
$ref: dataRef,
|
|
956
|
-
});
|
|
957
|
-
Object.assign(newNode.options, {
|
|
958
|
-
removable: false,
|
|
959
|
-
title: buttonText,
|
|
960
|
-
});
|
|
961
|
-
if (isNumber(JsonPointer.get(jsf.schema, schemaPointer, 0, -1).maxItems)) {
|
|
962
|
-
newNode.options.maxItems =
|
|
963
|
-
JsonPointer.get(jsf.schema, schemaPointer, 0, -1).maxItems;
|
|
964
|
-
}
|
|
965
|
-
|
|
966
|
-
// Add layout template to layoutRefLibrary
|
|
967
|
-
if (dataRef.length) {
|
|
968
|
-
if (!hasOwn(jsf.layoutRefLibrary, dataRef)) {
|
|
969
|
-
// Set to null first to prevent recursive reference from causing endless loop
|
|
970
|
-
jsf.layoutRefLibrary[dataRef] = null;
|
|
971
|
-
const newLayout = buildLayoutFromSchema(
|
|
972
|
-
jsf, widgetLibrary, null, schemaRef, '',
|
|
973
|
-
newNode.arrayItem, newNode.arrayItemType, true, true, dataPointer
|
|
974
|
-
);
|
|
975
|
-
if (newLayout) {
|
|
976
|
-
newLayout.recursiveReference = true;
|
|
977
|
-
jsf.layoutRefLibrary[dataRef] = newLayout;
|
|
978
|
-
} else {
|
|
979
|
-
delete jsf.layoutRefLibrary[dataRef];
|
|
980
|
-
}
|
|
981
|
-
} else if (!jsf.layoutRefLibrary[dataRef].recursiveReference) {
|
|
982
|
-
jsf.layoutRefLibrary[dataRef].recursiveReference = true;
|
|
983
|
-
}
|
|
984
|
-
}
|
|
985
|
-
}
|
|
986
|
-
return newNode;
|
|
987
|
-
}
|
|
988
|
-
|
|
989
|
-
/**
|
|
990
|
-
* 'mapLayout' function
|
|
991
|
-
*
|
|
992
|
-
* Creates a new layout by running each element in an existing layout through
|
|
993
|
-
* an iteratee. Recursively maps within array elements 'items' and 'tabs'.
|
|
994
|
-
* The iteratee is invoked with four arguments: (value, index, layout, path)
|
|
995
|
-
*
|
|
996
|
-
* The returned layout may be longer (or shorter) then the source layout.
|
|
997
|
-
*
|
|
998
|
-
* If an item from the source layout returns multiple items (as '*' usually will),
|
|
999
|
-
* this function will keep all returned items in-line with the surrounding items.
|
|
1000
|
-
*
|
|
1001
|
-
* If an item from the source layout causes an error and returns null, it is
|
|
1002
|
-
* skipped without error, and the function will still return all non-null items.
|
|
1003
|
-
*
|
|
1004
|
-
* // layout - the layout to map
|
|
1005
|
-
* // { (v: any, i?: number, l?: any, p?: string) => any }
|
|
1006
|
-
* function - the funciton to invoke on each element
|
|
1007
|
-
* // { string|string[] = '' } layoutPointer - the layoutPointer to layout, inside rootLayout
|
|
1008
|
-
* // { any[] = layout } rootLayout - the root layout, which conatins layout
|
|
1009
|
-
* //
|
|
1010
|
-
*/
|
|
1011
|
-
export function mapLayout(layout, fn, layoutPointer = '', rootLayout = layout) {
|
|
1012
|
-
let indexPad = 0;
|
|
1013
|
-
let newLayout: any[] = [];
|
|
1014
|
-
forEach(layout, (item, index) => {
|
|
1015
|
-
const realIndex = +index + indexPad;
|
|
1016
|
-
const newLayoutPointer = layoutPointer + '/' + realIndex;
|
|
1017
|
-
let newNode: any = copy(item);
|
|
1018
|
-
let itemsArray: any[] = [];
|
|
1019
|
-
if (isObject(item)) {
|
|
1020
|
-
if (hasOwn(item, 'tabs')) {
|
|
1021
|
-
item.items = item.tabs;
|
|
1022
|
-
delete item.tabs;
|
|
1023
|
-
}
|
|
1024
|
-
if (hasOwn(item, 'items')) {
|
|
1025
|
-
itemsArray = isArray(item.items) ? item.items : [item.items];
|
|
1026
|
-
}
|
|
1027
|
-
}
|
|
1028
|
-
if (itemsArray.length) {
|
|
1029
|
-
newNode.items = mapLayout(itemsArray, fn, newLayoutPointer + '/items', rootLayout);
|
|
1030
|
-
}
|
|
1031
|
-
newNode = fn(newNode, realIndex, newLayoutPointer, rootLayout);
|
|
1032
|
-
if (!isDefined(newNode)) {
|
|
1033
|
-
indexPad--;
|
|
1034
|
-
} else {
|
|
1035
|
-
if (isArray(newNode)) { indexPad += newNode.length - 1; }
|
|
1036
|
-
newLayout = newLayout.concat(newNode);
|
|
1037
|
-
}
|
|
1038
|
-
});
|
|
1039
|
-
return newLayout;
|
|
1040
|
-
}
|
|
1041
|
-
|
|
1042
|
-
/**
|
|
1043
|
-
* 'getLayoutNode' function
|
|
1044
|
-
* Copy a new layoutNode from layoutRefLibrary
|
|
1045
|
-
*
|
|
1046
|
-
* // refNode -
|
|
1047
|
-
* // layoutRefLibrary -
|
|
1048
|
-
* // { any = null } widgetLibrary -
|
|
1049
|
-
* // { any = null } nodeValue -
|
|
1050
|
-
* // copied layoutNode
|
|
1051
|
-
*/
|
|
1052
|
-
export function getLayoutNode(
|
|
1053
|
-
refNode, jsf, widgetLibrary: any = null, nodeValue: any = null
|
|
1054
|
-
) {
|
|
1055
|
-
|
|
1056
|
-
// If recursive reference and building initial layout, return Add button
|
|
1057
|
-
if (refNode.recursiveReference && widgetLibrary) {
|
|
1058
|
-
const newLayoutNode = cloneDeep(refNode);
|
|
1059
|
-
if (!newLayoutNode.options) { newLayoutNode.options = {}; }
|
|
1060
|
-
Object.assign(newLayoutNode, {
|
|
1061
|
-
recursiveReference: true,
|
|
1062
|
-
widget: widgetLibrary.getWidget('$ref'),
|
|
1063
|
-
});
|
|
1064
|
-
Object.assign(newLayoutNode.options, {
|
|
1065
|
-
removable: false,
|
|
1066
|
-
title: 'Add ' + newLayoutNode.$ref,
|
|
1067
|
-
});
|
|
1068
|
-
return newLayoutNode;
|
|
1069
|
-
|
|
1070
|
-
// Otherwise, return referenced layout
|
|
1071
|
-
} else {
|
|
1072
|
-
let newLayoutNode = jsf.layoutRefLibrary[refNode.$ref];
|
|
1073
|
-
// If value defined, build new node from schema (to set array lengths)
|
|
1074
|
-
if (isDefined(nodeValue)) {
|
|
1075
|
-
newLayoutNode = buildLayoutFromSchema(
|
|
1076
|
-
jsf, widgetLibrary, nodeValue,
|
|
1077
|
-
JsonPointer.toSchemaPointer(refNode.$ref, jsf.schema),
|
|
1078
|
-
refNode.$ref, newLayoutNode.arrayItem,
|
|
1079
|
-
newLayoutNode.arrayItemType, newLayoutNode.options.removable, false
|
|
1080
|
-
);
|
|
1081
|
-
} else {
|
|
1082
|
-
// If value not defined, copy node from layoutRefLibrary
|
|
1083
|
-
newLayoutNode = cloneDeep(newLayoutNode);
|
|
1084
|
-
JsonPointer.forEachDeep(newLayoutNode, (subNode, pointer) => {
|
|
1085
|
-
|
|
1086
|
-
// Reset all _id's in newLayoutNode to unique values
|
|
1087
|
-
if (hasOwn(subNode, '_id')) { subNode._id = uniqueId(); }
|
|
1088
|
-
|
|
1089
|
-
// If adding a recursive item, prefix current dataPointer
|
|
1090
|
-
// to all dataPointers in new layoutNode
|
|
1091
|
-
if (refNode.recursiveReference && hasOwn(subNode, 'dataPointer')) {
|
|
1092
|
-
subNode.dataPointer = refNode.dataPointer + subNode.dataPointer;
|
|
1093
|
-
}
|
|
1094
|
-
});
|
|
1095
|
-
}
|
|
1096
|
-
return newLayoutNode;
|
|
1097
|
-
}
|
|
1098
|
-
}
|
|
1099
|
-
|
|
1100
|
-
/**
|
|
1101
|
-
* 'buildTitleMap' function
|
|
1102
|
-
*
|
|
1103
|
-
* // titleMap -
|
|
1104
|
-
* // enumList -
|
|
1105
|
-
* // { boolean = true } fieldRequired -
|
|
1106
|
-
* // { boolean = true } flatList -
|
|
1107
|
-
* // { TitleMapItem[] }
|
|
1108
|
-
*/
|
|
1109
|
-
export function buildTitleMap(
|
|
1110
|
-
titleMap, enumList, fieldRequired = true, flatList = true
|
|
1111
|
-
) {
|
|
1112
|
-
let newTitleMap: TitleMapItem[] = [];
|
|
1113
|
-
let hasEmptyValue = false;
|
|
1114
|
-
if (titleMap) {
|
|
1115
|
-
if (isArray(titleMap)) {
|
|
1116
|
-
if (enumList) {
|
|
1117
|
-
for (const i of Object.keys(titleMap)) {
|
|
1118
|
-
if (isObject(titleMap[i])) { // JSON Form style
|
|
1119
|
-
const value = titleMap[i].value;
|
|
1120
|
-
if (enumList.includes(value)) {
|
|
1121
|
-
const name = titleMap[i].name;
|
|
1122
|
-
newTitleMap.push({ name, value });
|
|
1123
|
-
if (value === undefined || value === null) { hasEmptyValue = true; }
|
|
1124
|
-
}
|
|
1125
|
-
} else if (isString(titleMap[i])) { // React Jsonschema Form style
|
|
1126
|
-
if (i < enumList.length) {
|
|
1127
|
-
const name = titleMap[i];
|
|
1128
|
-
const value = enumList[i];
|
|
1129
|
-
newTitleMap.push({ name, value });
|
|
1130
|
-
if (value === undefined || value === null) { hasEmptyValue = true; }
|
|
1131
|
-
}
|
|
1132
|
-
}
|
|
1133
|
-
}
|
|
1134
|
-
} else { // If array titleMap and no enum list, just return the titleMap - Angular Schema Form style
|
|
1135
|
-
newTitleMap = titleMap;
|
|
1136
|
-
if (!fieldRequired) {
|
|
1137
|
-
hasEmptyValue = !!newTitleMap
|
|
1138
|
-
.filter(i => i.value === undefined || i.value === null)
|
|
1139
|
-
.length;
|
|
1140
|
-
}
|
|
1141
|
-
}
|
|
1142
|
-
} else if (enumList) { // Alternate JSON Form style, with enum list
|
|
1143
|
-
for (const i of Object.keys(enumList)) {
|
|
1144
|
-
const value = enumList[i];
|
|
1145
|
-
if (hasOwn(titleMap, value)) {
|
|
1146
|
-
const name = titleMap[value];
|
|
1147
|
-
newTitleMap.push({ name, value });
|
|
1148
|
-
if (value === undefined || value === null) { hasEmptyValue = true; }
|
|
1149
|
-
}
|
|
1150
|
-
}
|
|
1151
|
-
} else { // Alternate JSON Form style, without enum list
|
|
1152
|
-
for (const value of Object.keys(titleMap)) {
|
|
1153
|
-
const name = titleMap[value];
|
|
1154
|
-
newTitleMap.push({ name, value });
|
|
1155
|
-
if (value === undefined || value === null) { hasEmptyValue = true; }
|
|
1156
|
-
}
|
|
1157
|
-
}
|
|
1158
|
-
} else if (enumList) { // Build map from enum list alone
|
|
1159
|
-
for (const i of Object.keys(enumList)) {
|
|
1160
|
-
const name = enumList[i];
|
|
1161
|
-
const value = enumList[i];
|
|
1162
|
-
newTitleMap.push({ name, value });
|
|
1163
|
-
if (value === undefined || value === null) { hasEmptyValue = true; }
|
|
1164
|
-
}
|
|
1165
|
-
} else { // If no titleMap and no enum list, return default map of boolean values
|
|
1166
|
-
newTitleMap = [{ name: 'True', value: true }, { name: 'False', value: false }];
|
|
1167
|
-
}
|
|
1168
|
-
|
|
1169
|
-
// Does titleMap have groups?
|
|
1170
|
-
if (newTitleMap.some(title => hasOwn(title, 'group'))) {
|
|
1171
|
-
hasEmptyValue = false;
|
|
1172
|
-
|
|
1173
|
-
// If flatList = true, flatten items & update name to group: name
|
|
1174
|
-
if (flatList) {
|
|
1175
|
-
newTitleMap = newTitleMap.reduce((groupTitleMap, title) => {
|
|
1176
|
-
if (hasOwn(title, 'group')) {
|
|
1177
|
-
if (isArray(title.items)) {
|
|
1178
|
-
groupTitleMap = [
|
|
1179
|
-
...groupTitleMap,
|
|
1180
|
-
...title.items.map(item =>
|
|
1181
|
-
({ ...item, ...{ name: `${title.group}: ${item.name}` } })
|
|
1182
|
-
)
|
|
1183
|
-
];
|
|
1184
|
-
if (title.items.some(item => item.value === undefined || item.value === null)) {
|
|
1185
|
-
hasEmptyValue = true;
|
|
1186
|
-
}
|
|
1187
|
-
}
|
|
1188
|
-
if (hasOwn(title, 'name') && hasOwn(title, 'value')) {
|
|
1189
|
-
title.name = `${title.group}: ${title.name}`;
|
|
1190
|
-
delete title.group;
|
|
1191
|
-
groupTitleMap.push(title);
|
|
1192
|
-
if (title.value === undefined || title.value === null) {
|
|
1193
|
-
hasEmptyValue = true;
|
|
1194
|
-
}
|
|
1195
|
-
}
|
|
1196
|
-
} else {
|
|
1197
|
-
groupTitleMap.push(title);
|
|
1198
|
-
if (title.value === undefined || title.value === null) {
|
|
1199
|
-
hasEmptyValue = true;
|
|
1200
|
-
}
|
|
1201
|
-
}
|
|
1202
|
-
return groupTitleMap;
|
|
1203
|
-
}, []);
|
|
1204
|
-
|
|
1205
|
-
// If flatList = false, combine items from matching groups
|
|
1206
|
-
} else {
|
|
1207
|
-
newTitleMap = newTitleMap.reduce((groupTitleMap, title) => {
|
|
1208
|
-
if (hasOwn(title, 'group')) {
|
|
1209
|
-
if (title.group !== (groupTitleMap[groupTitleMap.length - 1] || {}).group) {
|
|
1210
|
-
groupTitleMap.push({ group: title.group, items: title.items || [] });
|
|
1211
|
-
}
|
|
1212
|
-
if (hasOwn(title, 'name') && hasOwn(title, 'value')) {
|
|
1213
|
-
groupTitleMap[groupTitleMap.length - 1].items
|
|
1214
|
-
.push({ name: title.name, value: title.value });
|
|
1215
|
-
if (title.value === undefined || title.value === null) {
|
|
1216
|
-
hasEmptyValue = true;
|
|
1217
|
-
}
|
|
1218
|
-
}
|
|
1219
|
-
} else {
|
|
1220
|
-
groupTitleMap.push(title);
|
|
1221
|
-
if (title.value === undefined || title.value === null) {
|
|
1222
|
-
hasEmptyValue = true;
|
|
1223
|
-
}
|
|
1224
|
-
}
|
|
1225
|
-
return groupTitleMap;
|
|
1226
|
-
}, []);
|
|
1227
|
-
}
|
|
1228
|
-
}
|
|
1229
|
-
if (!fieldRequired && !hasEmptyValue) {
|
|
1230
|
-
newTitleMap.unshift({ name: '<em>None</em>', value: null });
|
|
1231
|
-
}
|
|
1232
|
-
return newTitleMap;
|
|
1233
|
-
}
|