@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,601 @@
1
+ import { AbstractControl } from '@angular/forms';
2
+ import { from, Observable } from 'rxjs';
3
+
4
+ /**
5
+ * Validator utility function library:
6
+ *
7
+ * Validator and error utilities:
8
+ * _executeValidators, _executeAsyncValidators, _mergeObjects, _mergeErrors
9
+ *
10
+ * Individual value checking:
11
+ * isDefined, hasValue, isEmpty
12
+ *
13
+ * Individual type checking:
14
+ * isString, isNumber, isInteger, isBoolean, isFunction, isObject, isArray,
15
+ * isMap, isSet, isPromise, isObservable
16
+ *
17
+ * Multiple type checking and fixing:
18
+ * getType, isType, isPrimitive, toJavaScriptType, toSchemaType,
19
+ * _toPromise, toObservable
20
+ *
21
+ * Utility functions:
22
+ * inArray, xor
23
+ *
24
+ * Typescript types and interfaces:
25
+ * SchemaPrimitiveType, SchemaType, JavaScriptPrimitiveType, JavaScriptType,
26
+ * PrimitiveValue, PlainObject, IValidatorFn, AsyncIValidatorFn
27
+ *
28
+ * Note: 'IValidatorFn' is short for 'invertable validator function',
29
+ * which is a validator functions that accepts an optional second
30
+ * argument which, if set to TRUE, causes the validator to perform
31
+ * the opposite of its original function.
32
+ */
33
+
34
+ export type SchemaPrimitiveType =
35
+ 'string' | 'number' | 'integer' | 'boolean' | 'null';
36
+ export type SchemaType =
37
+ 'string' | 'number' | 'integer' | 'boolean' | 'null' | 'object' | 'array';
38
+ export type JavaScriptPrimitiveType =
39
+ 'string' | 'number' | 'boolean' | 'null' | 'undefined';
40
+ export type JavaScriptType =
41
+ 'string' | 'number' | 'boolean' | 'null' | 'undefined' | 'object' | 'array' |
42
+ 'map' | 'set' | 'arguments' | 'date' | 'error' | 'function' | 'json' |
43
+ 'math' | 'regexp'; // Note: this list is incomplete
44
+ export type PrimitiveValue = string | number | boolean | null | undefined;
45
+ export interface PlainObject { [k: string]: any; }
46
+
47
+ export type IValidatorFn = (c: AbstractControl, i?: boolean) => PlainObject;
48
+ export type AsyncIValidatorFn = (c: AbstractControl, i?: boolean) => any;
49
+
50
+ /**
51
+ * '_executeValidators' utility function
52
+ *
53
+ * Validates a control against an array of validators, and returns
54
+ * an array of the same length containing a combination of error messages
55
+ * (from invalid validators) and null values (from valid validators)
56
+ *
57
+ * // { AbstractControl } control - control to validate
58
+ * // { IValidatorFn[] } validators - array of validators
59
+ * // { boolean } invert - invert?
60
+ * // { PlainObject[] } - array of nulls and error message
61
+ */
62
+ export function _executeValidators(control, validators, invert = false) {
63
+ return validators.map(validator => validator(control, invert));
64
+ }
65
+
66
+ /**
67
+ * '_executeAsyncValidators' utility function
68
+ *
69
+ * Validates a control against an array of async validators, and returns
70
+ * an array of observabe results of the same length containing a combination of
71
+ * error messages (from invalid validators) and null values (from valid ones)
72
+ *
73
+ * // { AbstractControl } control - control to validate
74
+ * // { AsyncIValidatorFn[] } validators - array of async validators
75
+ * // { boolean } invert - invert?
76
+ * // - array of observable nulls and error message
77
+ */
78
+ export function _executeAsyncValidators(control, validators, invert = false) {
79
+ return validators.map(validator => validator(control, invert));
80
+ }
81
+
82
+ /**
83
+ * '_mergeObjects' utility function
84
+ *
85
+ * Recursively Merges one or more objects into a single object with combined keys.
86
+ * Automatically detects and ignores null and undefined inputs.
87
+ * Also detects duplicated boolean 'not' keys and XORs their values.
88
+ *
89
+ * // { PlainObject[] } objects - one or more objects to merge
90
+ * // { PlainObject } - merged object
91
+ */
92
+ export function _mergeObjects(...objects) {
93
+ const mergedObject: PlainObject = { };
94
+ for (const currentObject of objects) {
95
+ if (isObject(currentObject)) {
96
+ for (const key of Object.keys(currentObject)) {
97
+ const currentValue = currentObject[key];
98
+ const mergedValue = mergedObject[key];
99
+ mergedObject[key] = !isDefined(mergedValue) ? currentValue :
100
+ key === 'not' && isBoolean(mergedValue, 'strict') &&
101
+ isBoolean(currentValue, 'strict') ? xor(mergedValue, currentValue) :
102
+ getType(mergedValue) === 'object' && getType(currentValue) === 'object' ?
103
+ _mergeObjects(mergedValue, currentValue) :
104
+ currentValue;
105
+ }
106
+ }
107
+ }
108
+ return mergedObject;
109
+ }
110
+
111
+ /**
112
+ * '_mergeErrors' utility function
113
+ *
114
+ * Merges an array of objects.
115
+ * Used for combining the validator errors returned from 'executeValidators'
116
+ *
117
+ * // { PlainObject[] } arrayOfErrors - array of objects
118
+ * // { PlainObject } - merged object, or null if no usable input objectcs
119
+ */
120
+ export function _mergeErrors(arrayOfErrors) {
121
+ const mergedErrors = _mergeObjects(...arrayOfErrors);
122
+ return isEmpty(mergedErrors) ? null : mergedErrors;
123
+ }
124
+
125
+ /**
126
+ * 'isDefined' utility function
127
+ *
128
+ * Checks if a variable contains a value of any type.
129
+ * Returns true even for otherwise 'falsey' values of 0, '', and false.
130
+ *
131
+ * // value - the value to check
132
+ * // { boolean } - false if undefined or null, otherwise true
133
+ */
134
+ export function isDefined(value) {
135
+ return value !== undefined && value !== null;
136
+ }
137
+
138
+ /**
139
+ * 'hasValue' utility function
140
+ *
141
+ * Checks if a variable contains a value.
142
+ * Returs false for null, undefined, or a zero-length strng, '',
143
+ * otherwise returns true.
144
+ * (Stricter than 'isDefined' because it also returns false for '',
145
+ * though it stil returns true for otherwise 'falsey' values 0 and false.)
146
+ *
147
+ * // value - the value to check
148
+ * // { boolean } - false if undefined, null, or '', otherwise true
149
+ */
150
+ export function hasValue(value) {
151
+ return value !== undefined && value !== null && value !== '';
152
+ }
153
+
154
+ /**
155
+ * 'isEmpty' utility function
156
+ *
157
+ * Similar to !hasValue, but also returns true for empty arrays and objects.
158
+ *
159
+ * // value - the value to check
160
+ * // { boolean } - false if undefined, null, or '', otherwise true
161
+ */
162
+ export function isEmpty(value) {
163
+ if (isArray(value)) { return !value.length; }
164
+ if (isObject(value)) { return !Object.keys(value).length; }
165
+ return value === undefined || value === null || value === '';
166
+ }
167
+
168
+ /**
169
+ * 'isString' utility function
170
+ *
171
+ * Checks if a value is a string.
172
+ *
173
+ * // value - the value to check
174
+ * // { boolean } - true if string, false if not
175
+ */
176
+ export function isString(value) {
177
+ return typeof value === 'string';
178
+ }
179
+
180
+ /**
181
+ * 'isNumber' utility function
182
+ *
183
+ * Checks if a value is a regular number, numeric string, or JavaScript Date.
184
+ *
185
+ * // value - the value to check
186
+ * // { any = false } strict - if truthy, also checks JavaScript tyoe
187
+ * // { boolean } - true if number, false if not
188
+ */
189
+ export function isNumber(value, strict: any = false) {
190
+ if (strict && typeof value !== 'number') { return false; }
191
+ return !isNaN(value) && value !== value / 0;
192
+ }
193
+
194
+ /**
195
+ * 'isInteger' utility function
196
+ *
197
+ * Checks if a value is an integer.
198
+ *
199
+ * // value - the value to check
200
+ * // { any = false } strict - if truthy, also checks JavaScript tyoe
201
+ * // {boolean } - true if number, false if not
202
+ */
203
+ export function isInteger(value, strict: any = false) {
204
+ if (strict && typeof value !== 'number') { return false; }
205
+ return !isNaN(value) && value !== value / 0 && value % 1 === 0;
206
+ }
207
+
208
+ /**
209
+ * 'isBoolean' utility function
210
+ *
211
+ * Checks if a value is a boolean.
212
+ *
213
+ * // value - the value to check
214
+ * // { any = null } option - if 'strict', also checks JavaScript type
215
+ * if TRUE or FALSE, checks only for that value
216
+ * // { boolean } - true if boolean, false if not
217
+ */
218
+ export function isBoolean(value, option: any = null) {
219
+ if (option === 'strict') { return value === true || value === false; }
220
+ if (option === true) {
221
+ return value === true || value === 1 || value === 'true' || value === '1';
222
+ }
223
+ if (option === false) {
224
+ return value === false || value === 0 || value === 'false' || value === '0';
225
+ }
226
+ return value === true || value === 1 || value === 'true' || value === '1' ||
227
+ value === false || value === 0 || value === 'false' || value === '0';
228
+ }
229
+
230
+ export function isFunction(item: any): boolean {
231
+ return typeof item === 'function';
232
+ }
233
+
234
+ export function isObject(item: any): boolean {
235
+ return item !== null && typeof item === 'object';
236
+ }
237
+
238
+ export function isArray(item: any): boolean {
239
+ return Array.isArray(item);
240
+ }
241
+
242
+ export function isDate(item: any): boolean {
243
+ return !!item && Object.prototype.toString.call(item) === '[object Date]';
244
+ }
245
+
246
+ export function isMap(item: any): boolean {
247
+ return !!item && Object.prototype.toString.call(item) === '[object Map]';
248
+ }
249
+
250
+ export function isSet(item: any): boolean {
251
+ return !!item && Object.prototype.toString.call(item) === '[object Set]';
252
+ }
253
+
254
+ export function isSymbol(item: any): boolean {
255
+ return typeof item === 'symbol';
256
+ }
257
+
258
+ /**
259
+ * 'getType' function
260
+ *
261
+ * Detects the JSON Schema Type of a value.
262
+ * By default, detects numbers and integers even if formatted as strings.
263
+ * (So all integers are also numbers, and any number may also be a string.)
264
+ * However, it only detects true boolean values (to detect boolean values
265
+ * in non-boolean formats, use isBoolean() instead).
266
+ *
267
+ * If passed a second optional parameter of 'strict', it will only detect
268
+ * numbers and integers if they are formatted as JavaScript numbers.
269
+ *
270
+ * Examples:
271
+ * getType('10.5') = 'number'
272
+ * getType(10.5) = 'number'
273
+ * getType('10') = 'integer'
274
+ * getType(10) = 'integer'
275
+ * getType('true') = 'string'
276
+ * getType(true) = 'boolean'
277
+ * getType(null) = 'null'
278
+ * getType({ }) = 'object'
279
+ * getType([]) = 'array'
280
+ *
281
+ * getType('10.5', 'strict') = 'string'
282
+ * getType(10.5, 'strict') = 'number'
283
+ * getType('10', 'strict') = 'string'
284
+ * getType(10, 'strict') = 'integer'
285
+ * getType('true', 'strict') = 'string'
286
+ * getType(true, 'strict') = 'boolean'
287
+ *
288
+ * // value - value to check
289
+ * // { any = false } strict - if truthy, also checks JavaScript tyoe
290
+ * // { SchemaType }
291
+ */
292
+ export function getType(value, strict: any = false) {
293
+ if (!isDefined(value)) { return 'null'; }
294
+ if (isArray(value)) { return 'array'; }
295
+ if (isObject(value)) { return 'object'; }
296
+ if (isBoolean(value, 'strict')) { return 'boolean'; }
297
+ if (isInteger(value, strict)) { return 'integer'; }
298
+ if (isNumber(value, strict)) { return 'number'; }
299
+ if (isString(value) || (!strict && isDate(value))) { return 'string'; }
300
+ return null;
301
+ }
302
+
303
+ /**
304
+ * 'isType' function
305
+ *
306
+ * Checks wether an input (probably string) value contains data of
307
+ * a specified JSON Schema type
308
+ *
309
+ * // { PrimitiveValue } value - value to check
310
+ * // { SchemaPrimitiveType } type - type to check
311
+ * // { boolean }
312
+ */
313
+ export function isType(value, type) {
314
+ switch (type) {
315
+ case 'string':
316
+ return isString(value) || isDate(value);
317
+ case 'number':
318
+ return isNumber(value);
319
+ case 'integer':
320
+ return isInteger(value);
321
+ case 'boolean':
322
+ return isBoolean(value);
323
+ case 'null':
324
+ return !hasValue(value);
325
+ default:
326
+ console.error(`isType error: "${type}" is not a recognized type.`);
327
+ return null;
328
+ }
329
+ }
330
+
331
+ /**
332
+ * 'isPrimitive' function
333
+ *
334
+ * Checks wether an input value is a JavaScript primitive type:
335
+ * string, number, boolean, or null.
336
+ *
337
+ * // value - value to check
338
+ * // { boolean }
339
+ */
340
+ export function isPrimitive(value) {
341
+ return (isString(value) || isNumber(value) ||
342
+ isBoolean(value, 'strict') || value === null);
343
+ }
344
+
345
+ /**
346
+ *
347
+ * @param date
348
+ * @returns {string}
349
+ * exmaple:
350
+ * toDateString('2018-01-01') = '2018-01-01'
351
+ * toDateString('2018-01-30T00:00:00.000Z') = '2018-01-30'
352
+ */
353
+ export const toIsoString = (date: Date) => {
354
+ const day = date.getDate();
355
+ const month = date.getMonth() + 1;
356
+ const year = date.getFullYear();
357
+ return `${year}-${month < 10 ? '0' + month : month}-${day < 10 ? '0' + day : day}`;
358
+ }
359
+
360
+ /**
361
+ * 'toJavaScriptType' function
362
+ *
363
+ * Converts an input (probably string) value to a JavaScript primitive type -
364
+ * 'string', 'number', 'boolean', or 'null' - before storing in a JSON object.
365
+ *
366
+ * Does not coerce values (other than null), and only converts the types
367
+ * of values that would otherwise be valid.
368
+ *
369
+ * If the optional third parameter 'strictIntegers' is TRUE, and the
370
+ * JSON Schema type 'integer' is specified, it also verifies the input value
371
+ * is an integer and, if it is, returns it as a JaveScript number.
372
+ * If 'strictIntegers' is FALSE (or not set) the type 'integer' is treated
373
+ * exactly the same as 'number', and allows decimals.
374
+ *
375
+ * Valid Examples:
376
+ * toJavaScriptType('10', 'number' ) = 10 // '10' is a number
377
+ * toJavaScriptType('10', 'integer') = 10 // '10' is also an integer
378
+ * toJavaScriptType( 10, 'integer') = 10 // 10 is still an integer
379
+ * toJavaScriptType( 10, 'string' ) = '10' // 10 can be made into a string
380
+ * toJavaScriptType('10.5', 'number' ) = 10.5 // '10.5' is a number
381
+ *
382
+ * Invalid Examples:
383
+ * toJavaScriptType('10.5', 'integer') = null // '10.5' is not an integer
384
+ * toJavaScriptType( 10.5, 'integer') = null // 10.5 is still not an integer
385
+ *
386
+ * // { PrimitiveValue } value - value to convert
387
+ * // { SchemaPrimitiveType | SchemaPrimitiveType[] } types - types to convert to
388
+ * // { boolean = false } strictIntegers - if FALSE, treat integers as numbers
389
+ * // { PrimitiveValue }
390
+ */
391
+ export function toJavaScriptType(value, types, strictIntegers = true) {
392
+ if (!isDefined(value)) { return null; }
393
+ if (isString(types)) { types = [types]; }
394
+ if (strictIntegers && inArray('integer', types)) {
395
+ if (isInteger(value, 'strict')) { return value; }
396
+ if (isInteger(value)) { return parseInt(value, 10); }
397
+ }
398
+ if (inArray('number', types) || (!strictIntegers && inArray('integer', types))) {
399
+ if (isNumber(value, 'strict')) { return value; }
400
+ if (isNumber(value)) { return parseFloat(value); }
401
+ }
402
+ if (inArray('string', types)) {
403
+ if (isString(value)) { return value; }
404
+ // If value is a date, and types includes 'string',
405
+ // convert the date to a string
406
+ if (isDate(value)) { return toIsoString(value); }
407
+ if (isNumber(value)) { return value.toString(); }
408
+ }
409
+ // If value is a date, and types includes 'integer' or 'number',
410
+ // but not 'string', convert the date to a number
411
+ if (isDate(value) && (inArray('integer', types) || inArray('number', types))) {
412
+ return value.getTime();
413
+ }
414
+ if (inArray('boolean', types)) {
415
+ if (isBoolean(value, true)) { return true; }
416
+ if (isBoolean(value, false)) { return false; }
417
+ }
418
+ return null;
419
+ }
420
+
421
+ /**
422
+ * 'toSchemaType' function
423
+ *
424
+ * Converts an input (probably string) value to the "best" JavaScript
425
+ * equivalent available from an allowed list of JSON Schema types, which may
426
+ * contain 'string', 'number', 'integer', 'boolean', and/or 'null'.
427
+ * If necssary, it does progressively agressive type coersion.
428
+ * It will not return null unless null is in the list of allowed types.
429
+ *
430
+ * Number conversion examples:
431
+ * toSchemaType('10', ['number','integer','string']) = 10 // integer
432
+ * toSchemaType('10', ['number','string']) = 10 // number
433
+ * toSchemaType('10', ['string']) = '10' // string
434
+ * toSchemaType('10.5', ['number','integer','string']) = 10.5 // number
435
+ * toSchemaType('10.5', ['integer','string']) = '10.5' // string
436
+ * toSchemaType('10.5', ['integer']) = 10 // integer
437
+ * toSchemaType(10.5, ['null','boolean','string']) = '10.5' // string
438
+ * toSchemaType(10.5, ['null','boolean']) = true // boolean
439
+ *
440
+ * String conversion examples:
441
+ * toSchemaType('1.5x', ['boolean','number','integer','string']) = '1.5x' // string
442
+ * toSchemaType('1.5x', ['boolean','number','integer']) = '1.5' // number
443
+ * toSchemaType('1.5x', ['boolean','integer']) = '1' // integer
444
+ * toSchemaType('1.5x', ['boolean']) = true // boolean
445
+ * toSchemaType('xyz', ['number','integer','boolean','null']) = true // boolean
446
+ * toSchemaType('xyz', ['number','integer','null']) = null // null
447
+ * toSchemaType('xyz', ['number','integer']) = 0 // number
448
+ *
449
+ * Boolean conversion examples:
450
+ * toSchemaType('1', ['integer','number','string','boolean']) = 1 // integer
451
+ * toSchemaType('1', ['number','string','boolean']) = 1 // number
452
+ * toSchemaType('1', ['string','boolean']) = '1' // string
453
+ * toSchemaType('1', ['boolean']) = true // boolean
454
+ * toSchemaType('true', ['number','string','boolean']) = 'true' // string
455
+ * toSchemaType('true', ['boolean']) = true // boolean
456
+ * toSchemaType('true', ['number']) = 0 // number
457
+ * toSchemaType(true, ['number','string','boolean']) = true // boolean
458
+ * toSchemaType(true, ['number','string']) = 'true' // string
459
+ * toSchemaType(true, ['number']) = 1 // number
460
+ *
461
+ * // { PrimitiveValue } value - value to convert
462
+ * // { SchemaPrimitiveType | SchemaPrimitiveType[] } types - allowed types to convert to
463
+ * // { PrimitiveValue }
464
+ */
465
+ export function toSchemaType(value, types) {
466
+ if (!isArray(<SchemaPrimitiveType>types)) {
467
+ types = <SchemaPrimitiveType[]>[types];
468
+ }
469
+ if ((<SchemaPrimitiveType[]>types).includes('null') && !hasValue(value)) {
470
+ return null;
471
+ }
472
+ if ((<SchemaPrimitiveType[]>types).includes('boolean') && !isBoolean(value, 'strict')) {
473
+ return value;
474
+ }
475
+ if ((<SchemaPrimitiveType[]>types).includes('integer')) {
476
+ const testValue = toJavaScriptType(value, 'integer');
477
+ if (testValue !== null) { return +testValue; }
478
+ }
479
+ if ((<SchemaPrimitiveType[]>types).includes('number')) {
480
+ const testValue = toJavaScriptType(value, 'number');
481
+ if (testValue !== null) { return +testValue; }
482
+ }
483
+ if (
484
+ (isString(value) || isNumber(value, 'strict')) &&
485
+ (<SchemaPrimitiveType[]>types).includes('string')
486
+ ) { // Convert number to string
487
+ return toJavaScriptType(value, 'string');
488
+ }
489
+ if ((<SchemaPrimitiveType[]>types).includes('boolean') && isBoolean(value)) {
490
+ return toJavaScriptType(value, 'boolean');
491
+ }
492
+ if ((<SchemaPrimitiveType[]>types).includes('string')) { // Convert null & boolean to string
493
+ if (value === null) { return ''; }
494
+ const testValue = toJavaScriptType(value, 'string');
495
+ if (testValue !== null) { return testValue; }
496
+ }
497
+ if ((
498
+ (<SchemaPrimitiveType[]>types).includes('number') ||
499
+ (<SchemaPrimitiveType[]>types).includes('integer'))
500
+ ) {
501
+ if (value === true) { return 1; } // Convert boolean & null to number
502
+ if (value === false || value === null || value === '') { return 0; }
503
+ }
504
+ if ((<SchemaPrimitiveType[]>types).includes('number')) { // Convert mixed string to number
505
+ const testValue = parseFloat(<string>value);
506
+ if (!!testValue) { return testValue; }
507
+ }
508
+ if ((<SchemaPrimitiveType[]>types).includes('integer')) { // Convert string or number to integer
509
+ const testValue = parseInt(<string>value, 10);
510
+ if (!!testValue) { return testValue; }
511
+ }
512
+ if ((<SchemaPrimitiveType[]>types).includes('boolean')) { // Convert anything to boolean
513
+ return !!value;
514
+ }
515
+ if ((
516
+ (<SchemaPrimitiveType[]>types).includes('number') ||
517
+ (<SchemaPrimitiveType[]>types).includes('integer')
518
+ ) && !(<SchemaPrimitiveType[]>types).includes('null')
519
+ ) {
520
+ return 0; // If null not allowed, return 0 for non-convertable values
521
+ }
522
+ }
523
+
524
+ /**
525
+ * 'isPromise' function
526
+ *
527
+ * // object
528
+ * // { boolean }
529
+ */
530
+ export function isPromise(object): object is Promise<any> {
531
+ return !!object && typeof object.then === 'function';
532
+ }
533
+
534
+ /**
535
+ * 'isObservable' function
536
+ *
537
+ * // object
538
+ * // { boolean }
539
+ */
540
+ export function isObservable(object): object is Observable<any> {
541
+ return !!object && typeof object.subscribe === 'function';
542
+ }
543
+
544
+ /**
545
+ * '_toPromise' function
546
+ *
547
+ * // { object } object
548
+ * // { Promise<any> }
549
+ */
550
+ export function _toPromise(object): Promise<any> {
551
+ return isPromise(object) ? object : object.toPromise();
552
+ }
553
+
554
+ /**
555
+ * 'toObservable' function
556
+ *
557
+ * // { object } object
558
+ * // { Observable<any> }
559
+ */
560
+ export function toObservable(object): Observable<any> {
561
+ const observable = isPromise(object) ? from(object) : object;
562
+ if (isObservable(observable)) { return observable; }
563
+ console.error('toObservable error: Expected validator to return Promise or Observable.');
564
+ return new Observable();
565
+ }
566
+
567
+ /**
568
+ * 'inArray' function
569
+ *
570
+ * Searches an array for an item, or one of a list of items, and returns true
571
+ * as soon as a match is found, or false if no match.
572
+ *
573
+ * If the optional third parameter allIn is set to TRUE, and the item to find
574
+ * is an array, then the function returns true only if all elements from item
575
+ * are found in the array list, and false if any element is not found. If the
576
+ * item to find is not an array, setting allIn to TRUE has no effect.
577
+ *
578
+ * // { any|any[] } item - the item to search for
579
+ * // array - the array to search
580
+ * // { boolean = false } allIn - if TRUE, all items must be in array
581
+ * // { boolean } - true if item(s) in array, false otherwise
582
+ */
583
+ export function inArray(item, array, allIn = false) {
584
+ if (!isDefined(item) || !isArray(array)) { return false; }
585
+ return isArray(item) ?
586
+ item[allIn ? 'every' : 'some'](subItem => array.includes(subItem)) :
587
+ array.includes(item);
588
+ }
589
+
590
+ /**
591
+ * 'xor' utility function - exclusive or
592
+ *
593
+ * Returns true if exactly one of two values is truthy.
594
+ *
595
+ * // value1 - first value to check
596
+ * // value2 - second value to check
597
+ * // { boolean } - true if exactly one input value is truthy, false if not
598
+ */
599
+ export function xor(value1, value2) {
600
+ return (!!value1 && !value2) || (!value1 && !!value2);
601
+ }
@@ -0,0 +1,59 @@
1
+ import {
2
+ ChangeDetectionStrategy,
3
+ Component,
4
+ Input,
5
+ OnInit
6
+ } from '@angular/core';
7
+ import { JsonSchemaFormService } from '../json-schema-form.service';
8
+
9
+
10
+ @Component({
11
+ // tslint:disable-next-line:component-selector
12
+ selector: 'add-reference-widget',
13
+ template: `
14
+ <button *ngIf="showAddButton"
15
+ [class]="options?.fieldHtmlClass || ''"
16
+ [disabled]="options?.readonly"
17
+ (click)="addItem($event)">
18
+ <span *ngIf="options?.icon" [class]="options?.icon"></span>
19
+ <span *ngIf="options?.title" [innerHTML]="buttonText"></span>
20
+ </button>`,
21
+ changeDetection: ChangeDetectionStrategy.Default,
22
+ })
23
+ export class AddReferenceComponent implements OnInit {
24
+ options: any;
25
+ itemCount: number;
26
+ previousLayoutIndex: number[];
27
+ previousDataIndex: number[];
28
+ @Input() layoutNode: any;
29
+ @Input() layoutIndex: number[];
30
+ @Input() dataIndex: number[];
31
+
32
+ constructor(
33
+ private jsf: JsonSchemaFormService
34
+ ) { }
35
+
36
+ ngOnInit() {
37
+ this.options = this.layoutNode.options || {};
38
+ }
39
+
40
+ get showAddButton(): boolean {
41
+ return !this.layoutNode.arrayItem ||
42
+ this.layoutIndex[this.layoutIndex.length - 1] < this.options.maxItems;
43
+ }
44
+
45
+ addItem(event) {
46
+ event.preventDefault();
47
+ this.jsf.addItem(this);
48
+ }
49
+
50
+ get buttonText(): string {
51
+ const parent: any = {
52
+ dataIndex: this.dataIndex.slice(0, -1),
53
+ layoutIndex: this.layoutIndex.slice(0, -1),
54
+ layoutNode: this.jsf.getParentNode(this)
55
+ };
56
+ return parent.layoutNode.add ||
57
+ this.jsf.setArrayItemTitle(parent, this.layoutNode, this.itemCount);
58
+ }
59
+ }