@json-editor/json-editor 2.5.1 → 2.6.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/.eslintrc +5 -2
- package/.github/PULL_REQUEST_TEMPLATE.md +6 -6
- package/.github/workflows/build.yml +58 -0
- package/CHANGELOG.md +41 -1
- package/CONTRIBUTING.md +1 -1
- package/README.md +12 -4
- package/README_ADDON.md +65 -0
- package/config/codeceptjs_helpers.js +4 -0
- package/dist/jsoneditor.js +2 -2
- package/dist/nonmin/jsoneditor.js +3849 -3304
- package/dist/nonmin/jsoneditor.js.map +1 -1
- package/docs/index.html +2 -0
- package/docs/meta_schema.json +0 -1
- package/package.json +27 -26
- package/release-notes.md +9 -0
- package/src/core.js +1 -0
- package/src/defaults.js +182 -94
- package/src/editor.js +32 -12
- package/src/editors/array.js +20 -16
- package/src/editors/autocomplete.js +1 -0
- package/src/editors/base64.js +5 -4
- package/src/editors/button.js +2 -2
- package/src/editors/checkbox.js +3 -3
- package/src/editors/datetime.js +2 -2
- package/src/editors/info.js +1 -1
- package/src/editors/multiple.js +8 -2
- package/src/editors/multiselect.js +5 -3
- package/src/editors/object.js +32 -17
- package/src/editors/radio.js +9 -4
- package/src/editors/select.js +6 -6
- package/src/editors/signature.js +3 -2
- package/src/editors/starrating.js +5 -5
- package/src/editors/stepper.js +3 -0
- package/src/editors/string.js +6 -4
- package/src/editors/table.js +24 -14
- package/src/editors/upload.js +4 -3
- package/src/editors/uuid.js +1 -1
- package/src/iconlibs/index.js +2 -0
- package/src/iconlibs/openiconic.js +28 -0
- package/src/schemaloader.js +112 -28
- package/src/theme.js +36 -5
- package/src/themes/bootstrap3.js +4 -4
- package/src/themes/bootstrap4.js +41 -5
- package/src/themes/html.js +1 -2
- package/src/themes/materialize.js +1 -1
- package/src/themes/spectre.js +11 -8
- package/src/themes/tailwind.js +1 -1
- package/src/validator.js +129 -17
- package/tests/codeceptjs/core_test.js +204 -50
- package/tests/codeceptjs/editors/array_test.js +13 -11
- package/tests/codeceptjs/editors/button_test.js +6 -1
- package/tests/codeceptjs/editors/issues/issue-gh-812_test.js +32 -0
- package/tests/codeceptjs/editors/number_test.js +1 -1
- package/tests/codeceptjs/editors/object_test.js +194 -98
- package/tests/codeceptjs/editors/programmatic-changes_test.js +3 -1
- package/tests/codeceptjs/editors/radio_test.js +10 -0
- package/tests/codeceptjs/editors/rating_test.js +10 -11
- package/tests/codeceptjs/editors/select_test.js +17 -15
- package/tests/codeceptjs/editors/stepper_test.js +13 -1
- package/tests/codeceptjs/editors/string_test.js +81 -80
- package/tests/codeceptjs/editors/table-confirm-delete_test.js +58 -56
- package/tests/codeceptjs/editors/tabs_test.js +12 -10
- package/tests/codeceptjs/editors/validation_test.js +10 -8
- package/tests/codeceptjs/meta-schema_test.js +13 -14
- package/tests/codeceptjs/schemaloader_test.js +13 -0
- package/tests/codeceptjs/steps_file.js +4 -3
- package/tests/codeceptjs/themes_test.js +31 -0
- package/tests/docker-compose.yml +4 -3
- package/tests/fixtures/validation.json +382 -1
- package/tests/pages/_demo.html +2 -0
- package/tests/pages/anyof.html +80 -0
- package/tests/pages/form-name.html +108 -0
- package/tests/pages/issues/issue-gh-812.html +110 -0
- package/tests/pages/issues/issue-gh-848.html +81 -0
- package/tests/pages/meta_schema.json +0 -1
- package/tests/pages/object-no-additional-properties.html +27 -12
- package/tests/pages/object-required-properties.html +43 -9
- package/tests/pages/object-show-opt-in.html +110 -0
- package/tests/pages/object-with-dependencies-array.html +46 -0
- package/tests/pages/oneof.html +103 -0
- package/tests/pages/read-only.html +19 -4
- package/tests/pages/stepper-manual.html +57 -0
- package/tests/pages/themes.html +2 -0
- package/tests/pages/translate-property.html +247 -0
- package/tests/pages/urn.html +93 -0
- package/tests/unit/core.spec.js +2 -0
- package/tests/unit/defaults.spec.js +4 -2
- package/tests/unit/editor.spec.js +2 -0
- package/tests/unit/editors/array.spec.js +86 -0
- package/tests/unit/editors/table.spec.js +91 -0
- package/tests/unit/schemaloader.spec.js +362 -3
- package/tests/unit/validator.spec.js +14 -2
package/src/editors/string.js
CHANGED
|
@@ -6,12 +6,14 @@ export class StringEditor extends AbstractEditor {
|
|
|
6
6
|
super.register()
|
|
7
7
|
if (!this.input) return
|
|
8
8
|
this.input.setAttribute('name', this.formname)
|
|
9
|
+
this.input.setAttribute('aria-label', this.formname)
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
unregister () {
|
|
12
13
|
super.unregister()
|
|
13
14
|
if (!this.input) return
|
|
14
15
|
this.input.removeAttribute('name')
|
|
16
|
+
this.input.removeAttribute('aria-label')
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
setValue (value, initial, fromTemplate) {
|
|
@@ -70,8 +72,8 @@ export class StringEditor extends AbstractEditor {
|
|
|
70
72
|
|
|
71
73
|
build () {
|
|
72
74
|
if (!this.options.compact) this.header = this.label = this.theme.getFormInputLabel(this.getTitle(), this.isRequired())
|
|
73
|
-
if (this.schema.description) this.description = this.theme.getFormInputDescription(this.schema.description)
|
|
74
|
-
if (this.options.infoText) this.infoButton = this.theme.getInfoButton(this.options.infoText)
|
|
75
|
+
if (this.schema.description) this.description = this.theme.getFormInputDescription(this.translateProperty(this.schema.description))
|
|
76
|
+
if (this.options.infoText) this.infoButton = this.theme.getInfoButton(this.translateProperty(this.options.infoText))
|
|
75
77
|
|
|
76
78
|
this.format = this.schema.format
|
|
77
79
|
if (!this.format && this.schema.media && this.schema.media.type) {
|
|
@@ -127,7 +129,7 @@ export class StringEditor extends AbstractEditor {
|
|
|
127
129
|
} else if (this.options.input_width) this.input.style.width = this.options.input_width
|
|
128
130
|
|
|
129
131
|
if (this.schema.readOnly || this.schema.readonly || this.schema.template) {
|
|
130
|
-
this.
|
|
132
|
+
this.disable(true)
|
|
131
133
|
this.input.setAttribute('readonly', 'true')
|
|
132
134
|
}
|
|
133
135
|
|
|
@@ -201,7 +203,7 @@ export class StringEditor extends AbstractEditor {
|
|
|
201
203
|
input = this.theme.getRangeControl(this.input, this.theme.getRangeOutput(this.input, this.schema.default || Math.max(this.schema.minimum || 0, 0)))
|
|
202
204
|
}
|
|
203
205
|
|
|
204
|
-
this.control = this.theme.getFormControl(this.label, input, this.description, this.infoButton)
|
|
206
|
+
this.control = this.theme.getFormControl(this.label, input, this.description, this.infoButton, this.formname)
|
|
205
207
|
this.container.appendChild(this.control)
|
|
206
208
|
|
|
207
209
|
/* Any special formatting that needs to happen after the input is added to the dom */
|
package/src/editors/table.js
CHANGED
|
@@ -31,6 +31,7 @@ export class TableEditor extends ArrayEditor {
|
|
|
31
31
|
this.item_default = itemSchema.default || null
|
|
32
32
|
this.item_has_child_editors = itemSchema.properties || itemSchema.items
|
|
33
33
|
this.width = 12
|
|
34
|
+
this.array_controls_top = this.options.array_controls_top || this.jsoneditor.options.array_controls_top
|
|
34
35
|
super.preBuild()
|
|
35
36
|
}
|
|
36
37
|
|
|
@@ -52,12 +53,16 @@ export class TableEditor extends ArrayEditor {
|
|
|
52
53
|
if (!this.options.compact) {
|
|
53
54
|
this.header = document.createElement('label')
|
|
54
55
|
this.header.textContent = this.getTitle()
|
|
55
|
-
this.title = this.theme.getHeader(this.header)
|
|
56
|
+
this.title = this.theme.getHeader(this.header, this.getPathDepth())
|
|
56
57
|
this.container.appendChild(this.title)
|
|
58
|
+
if (this.options.infoText) {
|
|
59
|
+
this.infoButton = this.theme.getInfoButton(this.translateProperty(this.options.infoText))
|
|
60
|
+
this.container.appendChild(this.infoButton)
|
|
61
|
+
}
|
|
57
62
|
this.title_controls = this.theme.getHeaderButtonHolder()
|
|
58
63
|
this.title.appendChild(this.title_controls)
|
|
59
64
|
if (this.schema.description) {
|
|
60
|
-
this.description = this.theme.getDescription(this.schema.description)
|
|
65
|
+
this.description = this.theme.getDescription(this.translateProperty(this.schema.description))
|
|
61
66
|
this.container.appendChild(this.description)
|
|
62
67
|
}
|
|
63
68
|
this.panel = this.theme.getIndentedPanel()
|
|
@@ -71,7 +76,11 @@ export class TableEditor extends ArrayEditor {
|
|
|
71
76
|
|
|
72
77
|
this.panel.appendChild(this.table)
|
|
73
78
|
this.controls = this.theme.getButtonHolder()
|
|
74
|
-
|
|
79
|
+
if (this.array_controls_top) {
|
|
80
|
+
this.title.appendChild(this.controls)
|
|
81
|
+
} else {
|
|
82
|
+
this.panel.appendChild(this.controls)
|
|
83
|
+
}
|
|
75
84
|
|
|
76
85
|
if (this.item_has_child_editors) {
|
|
77
86
|
const ce = tmp.getChildEditors()
|
|
@@ -90,6 +99,7 @@ export class TableEditor extends ArrayEditor {
|
|
|
90
99
|
|
|
91
100
|
/* Row Controls column */
|
|
92
101
|
this.controls_header_cell = this.theme.getTableHeaderCell(' ')
|
|
102
|
+
this.controls_header_cell.setAttribute('aria-hidden', 'true')
|
|
93
103
|
this.header_row.appendChild(this.controls_header_cell)
|
|
94
104
|
|
|
95
105
|
/* Add controls */
|
|
@@ -307,11 +317,11 @@ export class TableEditor extends ArrayEditor {
|
|
|
307
317
|
this.rows[i].movedown_button = this._createMoveDownButton(i, controlsHolder)
|
|
308
318
|
}
|
|
309
319
|
|
|
310
|
-
if (value) this.rows[i].setValue(value)
|
|
320
|
+
if (typeof value !== 'undefined') this.rows[i].setValue(value)
|
|
311
321
|
}
|
|
312
322
|
|
|
313
323
|
_createDeleteButton (i, holder) {
|
|
314
|
-
const button = this.getButton('', 'delete',
|
|
324
|
+
const button = this.getButton('', 'delete', 'button_delete_row_title_short')
|
|
315
325
|
button.classList.add('delete', 'json-editor-btntype-delete')
|
|
316
326
|
button.setAttribute('data-i', i)
|
|
317
327
|
button.addEventListener('click', e => {
|
|
@@ -336,7 +346,7 @@ export class TableEditor extends ArrayEditor {
|
|
|
336
346
|
}
|
|
337
347
|
|
|
338
348
|
_createCopyButton (i, holder) {
|
|
339
|
-
const button = this.getButton('', 'copy',
|
|
349
|
+
const button = this.getButton('', 'copy', 'button_copy_row_title_short')
|
|
340
350
|
button.classList.add('copy', 'json-editor-btntype-copy')
|
|
341
351
|
button.setAttribute('data-i', i)
|
|
342
352
|
button.addEventListener('click', e => {
|
|
@@ -356,7 +366,7 @@ export class TableEditor extends ArrayEditor {
|
|
|
356
366
|
}
|
|
357
367
|
|
|
358
368
|
_createMoveUpButton (i, holder) {
|
|
359
|
-
const button = this.getButton('', 'moveup',
|
|
369
|
+
const button = this.getButton('', 'moveup', 'button_move_up_title')
|
|
360
370
|
button.classList.add('moveup', 'json-editor-btntype-move')
|
|
361
371
|
button.setAttribute('data-i', i)
|
|
362
372
|
button.addEventListener('click', e => {
|
|
@@ -377,7 +387,7 @@ export class TableEditor extends ArrayEditor {
|
|
|
377
387
|
}
|
|
378
388
|
|
|
379
389
|
_createMoveDownButton (i, holder) {
|
|
380
|
-
const button = this.getButton('', 'movedown',
|
|
390
|
+
const button = this.getButton('', 'movedown', 'button_move_down_title')
|
|
381
391
|
button.classList.add('movedown', 'json-editor-btntype-move')
|
|
382
392
|
button.setAttribute('data-i', i)
|
|
383
393
|
button.addEventListener('click', e => {
|
|
@@ -409,10 +419,10 @@ export class TableEditor extends ArrayEditor {
|
|
|
409
419
|
this.setVisibility(this.panel, this.collapsed)
|
|
410
420
|
if (this.collapsed) {
|
|
411
421
|
this.collapsed = false
|
|
412
|
-
this.setButtonText(e.currentTarget, '', 'collapse',
|
|
422
|
+
this.setButtonText(e.currentTarget, '', 'collapse', 'button_collapse')
|
|
413
423
|
} else {
|
|
414
424
|
this.collapsed = true
|
|
415
|
-
this.setButtonText(e.currentTarget, '', 'expand',
|
|
425
|
+
this.setButtonText(e.currentTarget, '', 'expand', 'button_expand')
|
|
416
426
|
}
|
|
417
427
|
})
|
|
418
428
|
|
|
@@ -436,13 +446,13 @@ export class TableEditor extends ArrayEditor {
|
|
|
436
446
|
}
|
|
437
447
|
|
|
438
448
|
_createToggleButton () {
|
|
439
|
-
const button = this.getButton('', 'collapse',
|
|
449
|
+
const button = this.getButton('', 'collapse', 'button_collapse')
|
|
440
450
|
button.classList.add('json-editor-btntype-toggle')
|
|
441
451
|
return button
|
|
442
452
|
}
|
|
443
453
|
|
|
444
454
|
_createAddRowButton () {
|
|
445
|
-
const button = this.getButton(this.getItemTitle(), 'add',
|
|
455
|
+
const button = this.getButton(this.getItemTitle(), 'add', 'button_add_row_title', [this.getItemTitle()])
|
|
446
456
|
button.classList.add('json-editor-btntype-add')
|
|
447
457
|
button.addEventListener('click', (e) => {
|
|
448
458
|
e.preventDefault()
|
|
@@ -459,7 +469,7 @@ export class TableEditor extends ArrayEditor {
|
|
|
459
469
|
}
|
|
460
470
|
|
|
461
471
|
_createDeleteLastRowButton () {
|
|
462
|
-
const button = this.getButton(
|
|
472
|
+
const button = this.getButton('button_delete_last', 'subtract', 'button_delete_last_title', [this.getItemTitle()])
|
|
463
473
|
button.classList.add('json-editor-btntype-deletelast')
|
|
464
474
|
button.addEventListener('click', (e) => {
|
|
465
475
|
e.preventDefault()
|
|
@@ -480,7 +490,7 @@ export class TableEditor extends ArrayEditor {
|
|
|
480
490
|
}
|
|
481
491
|
|
|
482
492
|
_createRemoveAllRowsButton () {
|
|
483
|
-
const button = this.getButton(
|
|
493
|
+
const button = this.getButton('button_delete_all', 'delete', 'button_delete_all_title')
|
|
484
494
|
button.classList.add('json-editor-btntype-deleteall')
|
|
485
495
|
button.addEventListener('click', (e) => {
|
|
486
496
|
e.preventDefault()
|
package/src/editors/upload.js
CHANGED
|
@@ -8,8 +8,8 @@ export class UploadEditor extends AbstractEditor {
|
|
|
8
8
|
|
|
9
9
|
build () {
|
|
10
10
|
if (!this.options.compact) this.header = this.label = this.theme.getFormInputLabel(this.getTitle(), this.isRequired())
|
|
11
|
-
if (this.schema.description) this.description = this.theme.getFormInputDescription(this.schema.description)
|
|
12
|
-
if (this.options.infoText) this.infoButton = this.theme.getInfoButton(this.options.infoText)
|
|
11
|
+
if (this.schema.description) this.description = this.theme.getFormInputDescription(this.translateProperty(this.schema.description))
|
|
12
|
+
if (this.options.infoText) this.infoButton = this.theme.getInfoButton(this.translateProperty(this.options.infoText))
|
|
13
13
|
|
|
14
14
|
/* Editor options */
|
|
15
15
|
this.options = this.expandCallbacks('upload', extend({}, {
|
|
@@ -189,6 +189,7 @@ export class UploadEditor extends AbstractEditor {
|
|
|
189
189
|
this.preview.appendChild(img)
|
|
190
190
|
}
|
|
191
191
|
img.onerror = error => {
|
|
192
|
+
// eslint-disable-next-line no-console
|
|
192
193
|
console.error('upload error', error, error.currentTarget)
|
|
193
194
|
}
|
|
194
195
|
img.src = this.container.querySelector('a').href
|
|
@@ -216,7 +217,7 @@ export class UploadEditor extends AbstractEditor {
|
|
|
216
217
|
file.formattedSize = `${parseFloat((file.size / (1024 ** i)).toFixed(2))} ${['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'][i]}`
|
|
217
218
|
} else file.formattedSize = '0 Bytes'
|
|
218
219
|
|
|
219
|
-
const uploadButton = this.getButton('
|
|
220
|
+
const uploadButton = this.getButton('button_upload', 'upload', 'button_upload')
|
|
220
221
|
uploadButton.addEventListener('click', (event) => {
|
|
221
222
|
event.preventDefault()
|
|
222
223
|
|
package/src/editors/uuid.js
CHANGED
package/src/iconlibs/index.js
CHANGED
|
@@ -7,6 +7,7 @@ import { fontawesome5Iconlib } from './fontawesome5.js'
|
|
|
7
7
|
// import { foundation3Iconlib } from './foundation3.js'
|
|
8
8
|
import { jqueryuiIconlib } from './jqueryui.js'
|
|
9
9
|
// import { materialiconsIconlib } from './materialicons.js'
|
|
10
|
+
import { openiconicIconlib } from './openiconic.js'
|
|
10
11
|
import { spectreIconlib } from './spectre.js'
|
|
11
12
|
|
|
12
13
|
export const iconlibs = {
|
|
@@ -19,5 +20,6 @@ export const iconlibs = {
|
|
|
19
20
|
// foundation3: foundation3Iconlib,
|
|
20
21
|
jqueryui: jqueryuiIconlib,
|
|
21
22
|
// materialicons: materialiconsIconlib,
|
|
23
|
+
openiconic: openiconicIconlib,
|
|
22
24
|
spectre: spectreIconlib
|
|
23
25
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { AbstractIconLib } from '../iconlib.js'
|
|
2
|
+
|
|
3
|
+
const iconPrefix = 'oi oi-'
|
|
4
|
+
const mapping = {
|
|
5
|
+
collapse: 'collapse-down',
|
|
6
|
+
expand: 'expand-right',
|
|
7
|
+
delete: 'trash',
|
|
8
|
+
edit: 'pencil',
|
|
9
|
+
add: 'plus',
|
|
10
|
+
subtract: 'minus',
|
|
11
|
+
cancel: 'ban',
|
|
12
|
+
save: 'file',
|
|
13
|
+
moveup: 'arrow-thick-top',
|
|
14
|
+
moveright: 'arrow-thick-right',
|
|
15
|
+
movedown: 'arrow-thick-bottom',
|
|
16
|
+
moveleft: 'arrow-thick-left',
|
|
17
|
+
copy: 'clipboard',
|
|
18
|
+
clear: 'circle-x',
|
|
19
|
+
time: 'clock',
|
|
20
|
+
calendar: 'calendar',
|
|
21
|
+
edit_properties: 'list'
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class openiconicIconlib extends AbstractIconLib {
|
|
25
|
+
constructor () {
|
|
26
|
+
super(iconPrefix, mapping)
|
|
27
|
+
}
|
|
28
|
+
}
|
package/src/schemaloader.js
CHANGED
|
@@ -98,6 +98,7 @@ export class SchemaLoader {
|
|
|
98
98
|
: ''
|
|
99
99
|
const ref = this._getRef(fetchUrl, refObj)
|
|
100
100
|
if (!this.refs[ref]) { /* if reference not found */
|
|
101
|
+
// eslint-disable-next-line no-console
|
|
101
102
|
console.warn(`reference:'${ref}' not found!`)
|
|
102
103
|
} else if (recurseAllOf && hasOwnProperty(this.refs[ref], 'allOf')) {
|
|
103
104
|
const allOf = this.refs[ref].allOf
|
|
@@ -135,7 +136,7 @@ export class SchemaLoader {
|
|
|
135
136
|
|
|
136
137
|
_expandSubSchema (subschema) {
|
|
137
138
|
/* Array of types */
|
|
138
|
-
if (Array.isArray(subschema)) return subschema.map(m => typeof
|
|
139
|
+
if (Array.isArray(subschema)) return subschema.map(m => typeof m === 'object' ? this.expandSchema(m) : m)
|
|
139
140
|
|
|
140
141
|
/* Schema */
|
|
141
142
|
return this.expandSchema(subschema)
|
|
@@ -177,10 +178,19 @@ export class SchemaLoader {
|
|
|
177
178
|
mergeRefs(this._getExternalRefs(value, fetchUrl))
|
|
178
179
|
}
|
|
179
180
|
})
|
|
181
|
+
|
|
182
|
+
if (schema.id && typeof schema.id === 'string' && schema.id.substr(0, 4) === 'urn:') {
|
|
183
|
+
this.refs[schema.id] = schema
|
|
184
|
+
} else if (schema.$id && typeof schema.$id === 'string' && schema.$id.substr(0, 4) === 'urn:') {
|
|
185
|
+
this.refs[schema.$id] = schema
|
|
186
|
+
}
|
|
187
|
+
|
|
180
188
|
return refs
|
|
181
189
|
}
|
|
182
190
|
|
|
183
191
|
_getFileBase (location) {
|
|
192
|
+
if (!location) return '/'
|
|
193
|
+
|
|
184
194
|
const { ajaxBase } = this.options
|
|
185
195
|
|
|
186
196
|
return typeof ajaxBase === 'undefined' ? this._getFileBaseFromFileLocation(location) : ajaxBase
|
|
@@ -192,64 +202,138 @@ export class SchemaLoader {
|
|
|
192
202
|
return `${pathItems.join('/')}/`
|
|
193
203
|
}
|
|
194
204
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
205
|
+
_joinUrl (url, fileBase) {
|
|
206
|
+
var fetchUrl = url
|
|
207
|
+
|
|
208
|
+
if (url.substr(0, 7) !== 'http://' &&
|
|
209
|
+
url.substr(0, 8) !== 'https://' &&
|
|
198
210
|
url.substr(0, 5) !== 'blob:' &&
|
|
199
211
|
url.substr(0, 5) !== 'data:' &&
|
|
212
|
+
url.substr(0, 1) !== '#' &&
|
|
200
213
|
url.substr(0, 1) !== '/'
|
|
214
|
+
) {
|
|
215
|
+
fetchUrl = fileBase + url
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// strip #fragment from URI, so json pointers resolve correctly #928
|
|
219
|
+
if (fetchUrl.indexOf('#') > 0) fetchUrl = fetchUrl.substr(0, fetchUrl.indexOf('#'))
|
|
220
|
+
|
|
221
|
+
return fetchUrl
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
_isUniformResourceName (uri) {
|
|
225
|
+
return uri.substr(0, 4) === 'urn:'
|
|
201
226
|
}
|
|
202
227
|
|
|
203
228
|
_loadExternalRefs (schema, callback, fetchUrl, fileBase) {
|
|
204
229
|
const refs = this._getExternalRefs(schema, fetchUrl)
|
|
205
|
-
let done =
|
|
230
|
+
let done = false; let waiting = 0
|
|
206
231
|
|
|
207
|
-
Object.keys(refs).forEach(
|
|
208
|
-
if (this.refs[
|
|
209
|
-
if (!this.options.ajax) throw new Error(`Must set ajax option to true to load external ref ${url}`)
|
|
210
|
-
this.refs[url] = 'loading'
|
|
211
|
-
waiting++
|
|
232
|
+
Object.keys(refs).forEach(uri => {
|
|
233
|
+
if (this.refs[uri]) return
|
|
212
234
|
|
|
213
|
-
|
|
235
|
+
if (this._isUniformResourceName(uri)) {
|
|
236
|
+
this.refs[uri] = 'loading'
|
|
237
|
+
waiting++
|
|
238
|
+
|
|
239
|
+
const urnResolver = this.options.urn_resolver
|
|
240
|
+
let urn = uri
|
|
241
|
+
if (typeof urnResolver !== 'function') {
|
|
242
|
+
// eslint-disable-next-line no-console
|
|
243
|
+
console.log(`No "urn_resolver" callback defined to resolve "${urn}"`)
|
|
244
|
+
throw new Error(`Must set urn_resolver option to a callback to resolve ${urn}`)
|
|
245
|
+
}
|
|
246
|
+
// theoretically a URN can contain a JSON pointer
|
|
247
|
+
if (urn.indexOf('#') > 0) urn = urn.substr(0, urn.indexOf('#'))
|
|
248
|
+
let response
|
|
249
|
+
try {
|
|
250
|
+
response = urnResolver(urn, responseText => {
|
|
251
|
+
try {
|
|
252
|
+
schema = JSON.parse(responseText)
|
|
253
|
+
} catch (e) {
|
|
254
|
+
// eslint-disable-next-line no-console
|
|
255
|
+
console.log(e)
|
|
256
|
+
throw new Error(`Failed to parse external ref ${urn}`)
|
|
257
|
+
}
|
|
258
|
+
if (!(typeof schema === 'boolean' || typeof schema === 'object') || schema === null || Array.isArray(schema)) {
|
|
259
|
+
throw new Error(`External ref does not contain a valid schema - ${urn}`)
|
|
260
|
+
}
|
|
261
|
+
this.refs[uri] = schema
|
|
262
|
+
this._getDefinitions(schema, `${urn}#/definitions/`)
|
|
263
|
+
this._loadExternalRefs(schema, () => {
|
|
264
|
+
waiting--
|
|
265
|
+
if (done && !waiting) {
|
|
266
|
+
callback()
|
|
267
|
+
}
|
|
268
|
+
}, uri, '/')
|
|
269
|
+
})
|
|
270
|
+
} catch (e) {
|
|
271
|
+
// eslint-disable-next-line no-console
|
|
272
|
+
console.log(e)
|
|
273
|
+
throw new Error(`Failed to parse external ref ${urn}`)
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (typeof response !== 'boolean') {
|
|
277
|
+
throw new Error(`External ref does not contain a valid schema - ${urn}`)
|
|
278
|
+
} else if (response !== true) {
|
|
279
|
+
throw new Error(`External ref did not resolve - ${urn}`)
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (!this.options.ajax) throw new Error(`Must set ajax option to true to load external ref ${uri}`)
|
|
286
|
+
this.refs[uri] = 'loading'
|
|
287
|
+
waiting++
|
|
288
|
+
let url = this._joinUrl(uri, fileBase)
|
|
214
289
|
|
|
215
290
|
const r = new XMLHttpRequest()
|
|
216
291
|
r.overrideMimeType('application/json')
|
|
217
|
-
r.open('GET',
|
|
292
|
+
r.open('GET', url, true)
|
|
218
293
|
if (this.options.ajaxCredentials) r.withCredentials = this.options.ajaxCredentials
|
|
219
294
|
r.onreadystatechange = () => {
|
|
220
295
|
if (r.readyState !== 4) return
|
|
221
296
|
/* Request succeeded */
|
|
222
297
|
if (r.status === 200) {
|
|
223
|
-
let
|
|
298
|
+
let schema
|
|
224
299
|
try {
|
|
225
|
-
|
|
300
|
+
schema = JSON.parse(r.responseText)
|
|
226
301
|
} catch (e) {
|
|
227
|
-
|
|
228
|
-
|
|
302
|
+
// eslint-disable-next-line no-console
|
|
303
|
+
console.log(e)
|
|
304
|
+
throw new Error(`Failed to parse external ref ${url}`)
|
|
229
305
|
}
|
|
230
|
-
if (!(typeof
|
|
231
|
-
throw new Error(`External ref does not contain a valid schema - ${
|
|
306
|
+
if (!(typeof schema === 'boolean' || typeof schema === 'object') || schema === null || Array.isArray(schema)) {
|
|
307
|
+
throw new Error(`External ref does not contain a valid schema - ${url}`)
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
this.refs[uri] = schema
|
|
311
|
+
const fileBase = this._getFileBaseFromFileLocation(url)
|
|
312
|
+
|
|
313
|
+
// add leading slash
|
|
314
|
+
if (url !== uri) {
|
|
315
|
+
const pathItems = url.split('/')
|
|
316
|
+
url = (uri.substr(0, 1) === '/' ? '/' : '') + pathItems.pop()
|
|
232
317
|
}
|
|
233
318
|
|
|
234
|
-
this.
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
done++
|
|
239
|
-
if (done >= waiting && !callbackFired) {
|
|
240
|
-
callbackFired = true
|
|
319
|
+
this._getDefinitions(schema, `${url}#/definitions/`)
|
|
320
|
+
this._loadExternalRefs(schema, () => {
|
|
321
|
+
waiting--
|
|
322
|
+
if (done && !waiting) {
|
|
241
323
|
callback()
|
|
242
324
|
}
|
|
243
|
-
},
|
|
325
|
+
}, url, fileBase)
|
|
244
326
|
} else {
|
|
245
327
|
/* Request failed */
|
|
246
|
-
|
|
247
|
-
|
|
328
|
+
// eslint-disable-next-line no-console
|
|
329
|
+
console.log(r)
|
|
330
|
+
throw new Error(`Failed to fetch ref via ajax - ${uri}`)
|
|
248
331
|
}
|
|
249
332
|
}
|
|
250
333
|
r.send()
|
|
251
334
|
})
|
|
252
335
|
|
|
336
|
+
done = true
|
|
253
337
|
if (!waiting) {
|
|
254
338
|
callback()
|
|
255
339
|
}
|
package/src/theme.js
CHANGED
|
@@ -105,7 +105,7 @@ export class AbstractTheme {
|
|
|
105
105
|
return el
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
getHeader (text) {
|
|
108
|
+
getHeader (text, pathDepth) {
|
|
109
109
|
const el = document.createElement('h3')
|
|
110
110
|
if (typeof text === 'string') {
|
|
111
111
|
el.textContent = text
|
|
@@ -254,13 +254,41 @@ export class AbstractTheme {
|
|
|
254
254
|
minusBtn.textContent = '-'
|
|
255
255
|
plusBtn.textContent = '+'
|
|
256
256
|
|
|
257
|
+
const initialize = (input, min) => {
|
|
258
|
+
if (min) {
|
|
259
|
+
input.value = Number(min)
|
|
260
|
+
} else {
|
|
261
|
+
input.value = Number(input.value)
|
|
262
|
+
}
|
|
263
|
+
input.setAttribute('initialized', '1')
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const min = input.getAttribute('min')
|
|
267
|
+
const max = input.getAttribute('max')
|
|
268
|
+
|
|
257
269
|
minusBtn.addEventListener('click', () => {
|
|
258
|
-
input.
|
|
270
|
+
if (!input.getAttribute('initialized')) {
|
|
271
|
+
initialize(input, min)
|
|
272
|
+
} else if (min) {
|
|
273
|
+
if (Number(input.value) > Number(min)) {
|
|
274
|
+
input.stepDown()
|
|
275
|
+
}
|
|
276
|
+
} else {
|
|
277
|
+
input.stepDown()
|
|
278
|
+
}
|
|
259
279
|
trigger(input, 'change')
|
|
260
280
|
})
|
|
261
281
|
|
|
262
282
|
plusBtn.addEventListener('click', () => {
|
|
263
|
-
input.
|
|
283
|
+
if (!input.getAttribute('initialized')) {
|
|
284
|
+
initialize(input, min)
|
|
285
|
+
} else if (max) {
|
|
286
|
+
if (Number(input.value) < Number(max)) {
|
|
287
|
+
input.stepUp()
|
|
288
|
+
}
|
|
289
|
+
} else {
|
|
290
|
+
input.stepUp()
|
|
291
|
+
}
|
|
264
292
|
trigger(input, 'change')
|
|
265
293
|
})
|
|
266
294
|
|
|
@@ -297,10 +325,13 @@ export class AbstractTheme {
|
|
|
297
325
|
|
|
298
326
|
}
|
|
299
327
|
|
|
300
|
-
getFormControl (label, input, description, infoText) {
|
|
328
|
+
getFormControl (label, input, description, infoText, formName) {
|
|
301
329
|
const el = document.createElement('div')
|
|
302
330
|
el.classList.add('form-control')
|
|
303
|
-
if (label)
|
|
331
|
+
if (label) {
|
|
332
|
+
el.appendChild(label)
|
|
333
|
+
if (formName) label.setAttribute('for', formName)
|
|
334
|
+
}
|
|
304
335
|
if ((input.type === 'checkbox' || input.type === 'radio') && label) {
|
|
305
336
|
input.style.width = 'auto'
|
|
306
337
|
label.insertBefore(input, label.firstChild)
|
package/src/themes/bootstrap3.js
CHANGED
|
@@ -50,7 +50,7 @@ export class bootstrap3Theme extends AbstractTheme {
|
|
|
50
50
|
return el
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
getFormControl (label, input, description) {
|
|
53
|
+
getFormControl (label, input, description, infoText) {
|
|
54
54
|
const group = document.createElement('div')
|
|
55
55
|
|
|
56
56
|
if (label && (input.type === 'checkbox' || input.type === 'radio')) {
|
|
@@ -62,6 +62,7 @@ export class bootstrap3Theme extends AbstractTheme {
|
|
|
62
62
|
if (label) {
|
|
63
63
|
label.classList.add('control-label')
|
|
64
64
|
group.appendChild(label)
|
|
65
|
+
if (infoText) label.appendChild(infoText)
|
|
65
66
|
}
|
|
66
67
|
group.appendChild(input)
|
|
67
68
|
}
|
|
@@ -94,7 +95,6 @@ export class bootstrap3Theme extends AbstractTheme {
|
|
|
94
95
|
tooltip.style.padding = '.5rem 1rem'
|
|
95
96
|
tooltip.style['border-radius'] = '.25rem'
|
|
96
97
|
tooltip.style.width = '25rem'
|
|
97
|
-
tooltip.style.transform = 'translateX(-27rem) translateY(-.5rem)'
|
|
98
98
|
tooltip.style.position = 'absolute'
|
|
99
99
|
tooltip.innerText = text
|
|
100
100
|
icon.onmouseover = () => {
|
|
@@ -172,14 +172,14 @@ export class bootstrap3Theme extends AbstractTheme {
|
|
|
172
172
|
getTabHolder (propertyName) {
|
|
173
173
|
const pName = (typeof propertyName === 'undefined') ? '' : propertyName
|
|
174
174
|
const el = document.createElement('div')
|
|
175
|
-
el.innerHTML = `<ul class='col-md-2 nav nav-pills nav-stacked' id='${pName}' role='tablist'></ul><div class='col-md-10 tab-content well well-small' id='${pName}'></div>`
|
|
175
|
+
el.innerHTML = `<ul class='col-md-2 nav nav-pills nav-stacked' id='${pName}' role='tablist'></ul><div class='col-md-10 tab-content active well well-small' id='${pName}'></div>`
|
|
176
176
|
return el
|
|
177
177
|
}
|
|
178
178
|
|
|
179
179
|
getTopTabHolder (propertyName) {
|
|
180
180
|
const pName = (typeof propertyName === 'undefined') ? '' : propertyName
|
|
181
181
|
const el = document.createElement('div')
|
|
182
|
-
el.innerHTML = `<ul class='nav nav-tabs' id='${pName}' role='tablist'></ul><div class='tab-content well well-small' id='${pName}'></div>`
|
|
182
|
+
el.innerHTML = `<ul class='nav nav-tabs' id='${pName}' role='tablist'></ul><div class='tab-content active well well-small' id='${pName}'></div>`
|
|
183
183
|
return el
|
|
184
184
|
}
|
|
185
185
|
|
package/src/themes/bootstrap4.js
CHANGED
|
@@ -123,13 +123,47 @@ export class bootstrap4Theme extends AbstractTheme {
|
|
|
123
123
|
minusBtn.textContent = '-'
|
|
124
124
|
plusBtn.textContent = '+'
|
|
125
125
|
|
|
126
|
+
const initialize = (input, min) => {
|
|
127
|
+
if (min) {
|
|
128
|
+
input.value = Number(min)
|
|
129
|
+
} else {
|
|
130
|
+
input.value = Number(input.value)
|
|
131
|
+
}
|
|
132
|
+
input.setAttribute('initialized', '1')
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const min = input.getAttribute('min')
|
|
136
|
+
const max = input.getAttribute('max')
|
|
137
|
+
|
|
138
|
+
input.addEventListener('change', () => {
|
|
139
|
+
if (!input.getAttribute('initialized')) {
|
|
140
|
+
input.setAttribute('initialized', '1')
|
|
141
|
+
}
|
|
142
|
+
})
|
|
143
|
+
|
|
126
144
|
minusBtn.addEventListener('click', () => {
|
|
127
|
-
input.
|
|
145
|
+
if (!input.getAttribute('initialized')) {
|
|
146
|
+
initialize(input, min)
|
|
147
|
+
} else if (min) {
|
|
148
|
+
if (Number(input.value) > Number(min)) {
|
|
149
|
+
input.stepDown()
|
|
150
|
+
}
|
|
151
|
+
} else {
|
|
152
|
+
input.stepDown()
|
|
153
|
+
}
|
|
128
154
|
trigger(input, 'change')
|
|
129
155
|
})
|
|
130
156
|
|
|
131
157
|
plusBtn.addEventListener('click', () => {
|
|
132
|
-
input.
|
|
158
|
+
if (!input.getAttribute('initialized')) {
|
|
159
|
+
initialize(input, min)
|
|
160
|
+
} else if (max) {
|
|
161
|
+
if (Number(input.value) < Number(max)) {
|
|
162
|
+
input.stepUp()
|
|
163
|
+
}
|
|
164
|
+
} else {
|
|
165
|
+
input.stepUp()
|
|
166
|
+
}
|
|
133
167
|
trigger(input, 'change')
|
|
134
168
|
})
|
|
135
169
|
|
|
@@ -218,6 +252,7 @@ export class bootstrap4Theme extends AbstractTheme {
|
|
|
218
252
|
if (window.jQuery && window.jQuery().tooltip) {
|
|
219
253
|
window.jQuery(button).tooltip()
|
|
220
254
|
} else {
|
|
255
|
+
// eslint-disable-next-line no-console
|
|
221
256
|
console.warn('Could not find popper jQuery plugin of Bootstrap.')
|
|
222
257
|
}
|
|
223
258
|
} else if (this.options.tooltip === 'css') {
|
|
@@ -370,12 +405,13 @@ export class bootstrap4Theme extends AbstractTheme {
|
|
|
370
405
|
return el
|
|
371
406
|
}
|
|
372
407
|
|
|
373
|
-
getHeader (text) {
|
|
408
|
+
getHeader (text, pathDepth) {
|
|
374
409
|
/* var cardHeader = document.createElement('div') */
|
|
375
410
|
/* cardHeader.classList.add('card-header') */
|
|
376
411
|
|
|
377
412
|
const el = document.createElement('h3')
|
|
378
413
|
el.classList.add('card-title')
|
|
414
|
+
el.classList.add('level-' + pathDepth)
|
|
379
415
|
|
|
380
416
|
if (typeof text === 'string') {
|
|
381
417
|
el.textContent = text
|
|
@@ -447,7 +483,7 @@ export class bootstrap4Theme extends AbstractTheme {
|
|
|
447
483
|
addInputError (input, text) {
|
|
448
484
|
if (!input.controlgroup) return
|
|
449
485
|
|
|
450
|
-
input.classList.add('is-invalid')
|
|
486
|
+
input.controlgroup.classList.add('is-invalid')
|
|
451
487
|
|
|
452
488
|
if (!input.errmsg) {
|
|
453
489
|
input.errmsg = document.createElement('p')
|
|
@@ -463,7 +499,7 @@ export class bootstrap4Theme extends AbstractTheme {
|
|
|
463
499
|
removeInputError (input) {
|
|
464
500
|
if (!input.errmsg) return
|
|
465
501
|
input.errmsg.style.display = 'none'
|
|
466
|
-
input.classList.remove('is-invalid')
|
|
502
|
+
input.controlgroup.classList.remove('is-invalid')
|
|
467
503
|
}
|
|
468
504
|
|
|
469
505
|
getTabHolder (propertyName) {
|