@json-editor/json-editor 2.5.2 → 2.6.1
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 +39 -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 +3711 -3324
- package/dist/nonmin/jsoneditor.js.map +1 -1
- package/docs/cleave.html +1 -1
- package/docs/datetime.html +1 -1
- package/docs/describedby.html +1 -1
- package/docs/index.html +4 -2
- package/docs/materialize_css.html +1 -1
- package/docs/meta_schema.json +0 -1
- package/docs/radio.html +1 -1
- package/docs/select2.html +1 -1
- package/docs/selectize.html +1 -1
- package/docs/starrating.html +1 -1
- package/docs/wysiwyg.html +1 -1
- package/package.json +27 -26
- package/release-notes.md +9 -9
- package/src/core.js +1 -0
- package/src/defaults.js +182 -94
- package/src/editor.js +28 -9
- 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 +35 -21
- 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/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 +6 -3
- package/src/themes/bootstrap3.js +4 -4
- package/src/themes/bootstrap4.js +11 -3
- 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 +128 -16
- package/tests/codeceptjs/core_test.js +125 -1
- 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 +216 -100
- 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/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 +56 -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/select.js
CHANGED
|
@@ -9,7 +9,7 @@ export class SelectEditor extends AbstractEditor {
|
|
|
9
9
|
const haveToUseDefaultValue = !!this.jsoneditor.options.use_default_values || typeof this.schema.default !== 'undefined'
|
|
10
10
|
|
|
11
11
|
if (
|
|
12
|
-
!this.enum_values.includes(sanitized) ||
|
|
12
|
+
(this.enum_options.length > 0 && !this.enum_values.includes(sanitized)) ||
|
|
13
13
|
(initial && !this.isRequired() && !haveToUseDefaultValue)
|
|
14
14
|
) {
|
|
15
15
|
sanitized = this.enum_values[0]
|
|
@@ -77,7 +77,7 @@ export class SelectEditor extends AbstractEditor {
|
|
|
77
77
|
|
|
78
78
|
this.schema.enum.forEach((option, i) => {
|
|
79
79
|
this.enum_options[i] = `${option}`
|
|
80
|
-
this.enum_display[i] = `${display[i] || option}`
|
|
80
|
+
this.enum_display[i] = `${this.translateProperty(display[i]) || option}`
|
|
81
81
|
this.enum_values[i] = this.typecast(option)
|
|
82
82
|
})
|
|
83
83
|
|
|
@@ -162,15 +162,15 @@ export class SelectEditor extends AbstractEditor {
|
|
|
162
162
|
|
|
163
163
|
build () {
|
|
164
164
|
if (!this.options.compact) this.header = this.label = this.theme.getFormInputLabel(this.getTitle(), this.isRequired())
|
|
165
|
-
if (this.schema.description) this.description = this.theme.getFormInputDescription(this.schema.description)
|
|
166
|
-
if (this.options.infoText) this.infoButton = this.theme.getInfoButton(this.options.infoText)
|
|
165
|
+
if (this.schema.description) this.description = this.theme.getFormInputDescription(this.translateProperty(this.schema.description))
|
|
166
|
+
if (this.options.infoText) this.infoButton = this.theme.getInfoButton(this.translateProperty(this.options.infoText))
|
|
167
167
|
if (this.options.compact) this.container.classList.add('compact')
|
|
168
168
|
|
|
169
169
|
this.input = this.theme.getSelectInput(this.enum_options, false)
|
|
170
170
|
this.theme.setSelectOptions(this.input, this.enum_options, this.enum_display)
|
|
171
171
|
|
|
172
172
|
if (this.schema.readOnly || this.schema.readonly) {
|
|
173
|
-
this.
|
|
173
|
+
this.disable(true)
|
|
174
174
|
this.input.disabled = true
|
|
175
175
|
}
|
|
176
176
|
|
|
@@ -330,8 +330,8 @@ export class SelectEditor extends AbstractEditor {
|
|
|
330
330
|
enable () {
|
|
331
331
|
if (!this.always_disabled) {
|
|
332
332
|
this.input.disabled = false
|
|
333
|
+
super.enable()
|
|
333
334
|
}
|
|
334
|
-
super.enable()
|
|
335
335
|
}
|
|
336
336
|
|
|
337
337
|
disable (alwaysDisabled) {
|
package/src/editors/signature.js
CHANGED
|
@@ -6,7 +6,7 @@ import { StringEditor } from './string.js'
|
|
|
6
6
|
export class SignatureEditor extends StringEditor {
|
|
7
7
|
build () {
|
|
8
8
|
if (!this.options.compact) this.header = this.label = this.theme.getFormInputLabel(this.getTitle(), this.isRequired())
|
|
9
|
-
if (this.schema.description) this.description = this.theme.getFormInputDescription(this.schema.description)
|
|
9
|
+
if (this.schema.description) this.description = this.theme.getFormInputDescription(this.translateProperty(this.schema.description))
|
|
10
10
|
const formname = this.formname.replace(/\W/g, '')
|
|
11
11
|
|
|
12
12
|
if (typeof SignaturePad === 'function') {
|
|
@@ -53,7 +53,8 @@ export class SignatureEditor extends StringEditor {
|
|
|
53
53
|
if (this.options.compact) this.container.setAttribute('class', `${this.container.getAttribute('class')} compact`)
|
|
54
54
|
|
|
55
55
|
if (this.schema.readOnly || this.schema.readonly) {
|
|
56
|
-
this.
|
|
56
|
+
this.disable(true)
|
|
57
|
+
|
|
57
58
|
Array.from(this.inputs).forEach(input => {
|
|
58
59
|
canvas.setAttribute('readOnly', 'readOnly')
|
|
59
60
|
input.disabled = true
|
|
@@ -4,8 +4,8 @@ import rules from './starrating.css.js'
|
|
|
4
4
|
export class StarratingEditor extends StringEditor {
|
|
5
5
|
build () {
|
|
6
6
|
if (!this.options.compact) this.header = this.label = this.theme.getFormInputLabel(this.getTitle(), this.isRequired())
|
|
7
|
-
if (this.schema.description) this.description = this.theme.getFormInputDescription(this.schema.description)
|
|
8
|
-
if (this.options.infoText) this.infoButton = this.theme.getInfoButton(this.options.infoText)
|
|
7
|
+
if (this.schema.description) this.description = this.theme.getFormInputDescription(this.translateProperty(this.schema.description))
|
|
8
|
+
if (this.options.infoText) this.infoButton = this.theme.getInfoButton(this.translateProperty(this.options.infoText))
|
|
9
9
|
if (this.options.compact) this.container.classList.add('compact')
|
|
10
10
|
|
|
11
11
|
this.ratingContainer = document.createElement('div')
|
|
@@ -59,7 +59,7 @@ export class StarratingEditor extends StringEditor {
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
if (this.schema.readOnly || this.schema.readonly) {
|
|
62
|
-
this.
|
|
62
|
+
this.disable(true)
|
|
63
63
|
for (let j = 0; j < this.radioGroup.length; j++) {
|
|
64
64
|
this.radioGroup[j].disabled = true
|
|
65
65
|
}
|
|
@@ -83,7 +83,7 @@ export class StarratingEditor extends StringEditor {
|
|
|
83
83
|
this.radioGroup[i].disabled = false
|
|
84
84
|
}
|
|
85
85
|
this.ratingContainer.classList.remove('readonly')
|
|
86
|
-
|
|
86
|
+
this.disabled = false
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
|
|
@@ -93,7 +93,7 @@ export class StarratingEditor extends StringEditor {
|
|
|
93
93
|
this.radioGroup[i].disabled = true
|
|
94
94
|
}
|
|
95
95
|
this.ratingContainer.classList.add('readonly')
|
|
96
|
-
|
|
96
|
+
this.disabled = true
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
destroy () {
|
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
|
|
@@ -325,10 +325,13 @@ export class AbstractTheme {
|
|
|
325
325
|
|
|
326
326
|
}
|
|
327
327
|
|
|
328
|
-
getFormControl (label, input, description, infoText) {
|
|
328
|
+
getFormControl (label, input, description, infoText, formName) {
|
|
329
329
|
const el = document.createElement('div')
|
|
330
330
|
el.classList.add('form-control')
|
|
331
|
-
if (label)
|
|
331
|
+
if (label) {
|
|
332
|
+
el.appendChild(label)
|
|
333
|
+
if (formName) label.setAttribute('for', formName)
|
|
334
|
+
}
|
|
332
335
|
if ((input.type === 'checkbox' || input.type === 'radio') && label) {
|
|
333
336
|
input.style.width = 'auto'
|
|
334
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
|
|