@json-editor/json-editor 2.15.1 → 2.15.3

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 (68) hide show
  1. package/.env +1 -1
  2. package/.github/workflows/build.yml +5 -5
  3. package/CHANGELOG.md +21 -0
  4. package/CONTRIBUTING.md +10 -0
  5. package/README.md +27 -0
  6. package/dist/jsoneditor.js +1 -1
  7. package/dist/jsoneditor.js.LICENSE.txt +1 -1
  8. package/dist/nonmin/jsoneditor.js +497 -150
  9. package/dist/nonmin/jsoneditor.js.map +1 -1
  10. package/docs/form-submission.html +1 -1
  11. package/docs/index.html +18 -0
  12. package/package.json +1 -1
  13. package/src/core.js +11 -0
  14. package/src/defaults.js +2 -1
  15. package/src/editor.js +27 -16
  16. package/src/editors/ace.js +1 -0
  17. package/src/editors/array/choices.js +1 -0
  18. package/src/editors/array/select2.js +2 -0
  19. package/src/editors/array/selectize.js +2 -0
  20. package/src/editors/array.js +81 -0
  21. package/src/editors/base64.js +2 -0
  22. package/src/editors/checkbox.js +13 -1
  23. package/src/editors/choices.js +2 -0
  24. package/src/editors/colorpicker.js +2 -0
  25. package/src/editors/datetime.js +2 -0
  26. package/src/editors/describedby.js +2 -0
  27. package/src/editors/enum.js +3 -1
  28. package/src/editors/hidden.js +2 -0
  29. package/src/editors/jodit.js +2 -0
  30. package/src/editors/multiple.js +2 -0
  31. package/src/editors/multiselect.js +2 -0
  32. package/src/editors/object.js +10 -3
  33. package/src/editors/radio.js +2 -0
  34. package/src/editors/sceditor.js +2 -0
  35. package/src/editors/select.js +2 -1
  36. package/src/editors/select2.js +2 -0
  37. package/src/editors/selectize.js +2 -0
  38. package/src/editors/signature.js +2 -0
  39. package/src/editors/simplemde.js +3 -1
  40. package/src/editors/starrating.js +2 -0
  41. package/src/editors/string.js +2 -0
  42. package/src/editors/table.js +19 -2
  43. package/src/editors/upload.js +2 -0
  44. package/src/editors/uuid.js +2 -0
  45. package/src/resolvers.js +1 -1
  46. package/src/theme.js +23 -0
  47. package/src/themes/bootstrap3.css +53 -0
  48. package/src/themes/bootstrap3.css.js +1 -1
  49. package/src/themes/bootstrap3.js +30 -0
  50. package/src/themes/bootstrap4.js +27 -0
  51. package/src/themes/bootstrap5.js +28 -0
  52. package/src/themes/spectre.js +28 -0
  53. package/src/themes/tailwind.css +54 -0
  54. package/src/themes/tailwind.css.js +1 -1
  55. package/src/themes/tailwind.js +26 -0
  56. package/tests/codeceptjs/core_test.js +28 -0
  57. package/tests/codeceptjs/editors/multiple_test.js +27 -0
  58. package/tests/codeceptjs/issues/issue-gh-1559_test.js +15 -0
  59. package/tests/codeceptjs/issues/issue-gh-1562_test.js +12 -0
  60. package/tests/codeceptjs/issues/issue-gh-1586_test.js +15 -0
  61. package/tests/pages/editor-show-validation-errors.html +54 -0
  62. package/tests/pages/enforce-const.html +10 -18
  63. package/tests/pages/issues/issue-gh-1559.html +68 -0
  64. package/tests/pages/issues/issue-gh-1562.html +170 -0
  65. package/tests/pages/issues/issue-gh-1586.html +48 -0
  66. package/tests/pages/opt-in-widget.html +134 -0
  67. package/tests/pages/switcher-option.html +69 -0
  68. package/tests/docker-compose-local.yml +0 -4
@@ -1,4 +1,4 @@
1
- import { ArrayEditor } from './array.js'
1
+ import { ArrayEditor, supportDragDrop } from './array.js'
2
2
  import { extend, generateUUID, trigger } from '../utilities.js'
3
3
 
4
4
  export class TableEditor extends ArrayEditor {
@@ -187,6 +187,8 @@ export class TableEditor extends ArrayEditor {
187
187
  }
188
188
 
189
189
  setValue (value = [], initial) {
190
+ value = this.applyConstFilter(value)
191
+
190
192
  /* Make sure value has between minItems and maxItems items in it */
191
193
  value = this.ensureArraySize(value)
192
194
 
@@ -221,7 +223,6 @@ export class TableEditor extends ArrayEditor {
221
223
  if (numrowsChanged || initial) this.refreshRowButtons()
222
224
 
223
225
  this.onChange()
224
-
225
226
  /* TODO: sortable */
226
227
  }
227
228
 
@@ -321,6 +322,8 @@ export class TableEditor extends ArrayEditor {
321
322
  this.rows[i].movedown_button = this._createMoveDownButton(i, controlsHolder)
322
323
  }
323
324
 
325
+ this._supportDragDrop(this.rows[i].row)
326
+
324
327
  if (typeof value !== 'undefined') this.rows[i].setValue(value)
325
328
 
326
329
  return this.rows[i]
@@ -434,6 +437,20 @@ export class TableEditor extends ArrayEditor {
434
437
  return button
435
438
  }
436
439
 
440
+ _supportDragDrop (tab) {
441
+ supportDragDrop(tab, (i, j) => {
442
+ const rows = this.getValue()
443
+ const tmp = rows[i]
444
+ rows.splice(i, 1)
445
+ rows.splice(j, 0, tmp)
446
+
447
+ this.setValue(rows)
448
+ this.onChange(true)
449
+
450
+ this.jsoneditor.trigger('moveRow', this.rows[j])
451
+ }, { useTrigger: true })
452
+ }
453
+
437
454
  addControls () {
438
455
  this.collapsed = false
439
456
  this.toggle_button = this._createToggleButton()
@@ -276,6 +276,8 @@ export class UploadEditor extends AbstractEditor {
276
276
  }
277
277
 
278
278
  setValue (val) {
279
+ val = this.applyConstFilter(val)
280
+
279
281
  if (this.value !== val) {
280
282
  this.value = val
281
283
  this.input.value = this.value
@@ -31,6 +31,8 @@ export class UuidEditor extends StringEditor {
31
31
  }
32
32
 
33
33
  setValue (value, initial, fromTemplate) {
34
+ value = this.applyConstFilter(value)
35
+
34
36
  if (!this.testUuid(value)) value = this.uuid
35
37
  this.uuid = value
36
38
  super.setValue(value, initial, fromTemplate)
package/src/resolvers.js CHANGED
@@ -81,7 +81,7 @@ const arraysOfStrings = (schema, je) => {
81
81
  }
82
82
 
83
83
  /* Use the multiple editor for schemas with `oneOf` or `anyOf` set */
84
- const oneOf = schema => (schema.oneOf || schema.anyOf) && 'multiple'
84
+ const oneOf = schema => (schema.oneOf || schema.anyOf) && (schema.options?.switcher ?? true) === true && 'multiple'
85
85
 
86
86
  /* Use the multiple editor for schemas with `if` set */
87
87
  const ifThenElse = schema => (schema.if) && 'multiple'
package/src/theme.js CHANGED
@@ -23,6 +23,29 @@ export class AbstractTheme {
23
23
  return document.createElement('div')
24
24
  }
25
25
 
26
+ getOptInCheckbox (formname) {
27
+ const container = document.createElement('span')
28
+
29
+ const label = this.getHiddenLabel(formname + ' opt-in')
30
+ label.setAttribute('for', formname + '-opt-in')
31
+ label.textContent = formname + '-opt-in'
32
+
33
+ const checkbox = document.createElement('input')
34
+ checkbox.setAttribute('type', 'checkbox')
35
+ checkbox.setAttribute('style', 'margin: 0 10px 0 0;')
36
+ checkbox.setAttribute('id', formname + '-opt-in')
37
+ checkbox.classList.add('json-editor-opt-in')
38
+
39
+ container.appendChild(checkbox)
40
+ container.appendChild(label)
41
+
42
+ return { label, checkbox, container }
43
+ }
44
+
45
+ getOptInSwitch (formname) {
46
+ return this.getOptInCheckbox()
47
+ }
48
+
26
49
  getFloatRightLinkHolder () {
27
50
  const el = document.createElement('div')
28
51
  el.classList.add('je-float-right-linkholder')
@@ -0,0 +1,53 @@
1
+ .switch {
2
+ position: relative;
3
+ display: inline-block;
4
+ width: 28px;
5
+ height: 16px;
6
+ margin-right: 10px;
7
+ }
8
+
9
+ .switch input {
10
+ opacity: 0;
11
+ width: 0;
12
+ height: 0;
13
+ }
14
+
15
+ .switch-slider {
16
+ position: absolute;
17
+ cursor: pointer;
18
+ top: 0;
19
+ left: 0;
20
+ right: 0;
21
+ bottom: 0;
22
+ background-color: #ccc;
23
+ transition: .1s;
24
+ border-radius: 34px;
25
+ }
26
+
27
+ .switch-slider:before {
28
+ position: absolute;
29
+ content: "";
30
+ height: 12px;
31
+ width: 12px;
32
+ left: 1px;
33
+ top: 2px;
34
+ background-color: white;
35
+ transition: .1s;
36
+ border-radius: 50%;
37
+ }
38
+
39
+ input:checked + .switch-slider {
40
+ background-color: #2196F3;
41
+ }
42
+
43
+ input:focus + .switch-slider {
44
+ box-shadow: 0 0 1px #2196F3;
45
+ }
46
+
47
+ input:checked + .switch-slider:before {
48
+ transform: translateX(12px);
49
+ }
50
+
51
+ input:disabled + .switch-slider {
52
+ opacity: 0.5;
53
+ }
@@ -1,3 +1,3 @@
1
1
  /* eslint-disable */
2
- export default {}
2
+ export default {".switch":"position:relative;display:inline-block;width:28px;height:16px;margin-right:10px",".switch input":"opacity:0;width:0;height:0",".switch-slider":"position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:%23ccc;transition:.1s;border-radius:34px",".switch-slider:before":"position:absolute;content:%22%22;height:12px;width:12px;left:1px;top:2px;background-color:white;transition:.1s;border-radius:50%25","input:checked + .switch-slider":"background-color:%232196F3","input:focus + .switch-slider":"box-shadow:0%200%201px%20%232196F3","input:checked + .switch-slider:before":"transform:translateX(12px)","input:disabled + .switch-slider":"opacity:0.5"}
3
3
  /* eslint-enable */
@@ -2,6 +2,32 @@ import { AbstractTheme } from '../theme.js'
2
2
  import rules from './bootstrap3.css.js'
3
3
 
4
4
  export class bootstrap3Theme extends AbstractTheme {
5
+ getOptInSwitch (formname) {
6
+ const label = this.getHiddenLabel(formname + ' opt-in')
7
+ label.setAttribute('for', formname + '-opt-in')
8
+
9
+ const container = document.createElement('label')
10
+ container.classList.add('switch')
11
+
12
+ const checkbox = document.createElement('input')
13
+ checkbox.setAttribute('type', 'checkbox')
14
+ checkbox.setAttribute('id', formname + '-opt-in')
15
+ checkbox.classList.add('json-editor-opt-in')
16
+
17
+ const slider = document.createElement('span')
18
+ slider.classList.add('switch-slider')
19
+
20
+ const switchLabelText = document.createElement('span')
21
+ switchLabelText.classList.add('sr-only')
22
+ switchLabelText.textContent = formname + '-opt-in'
23
+
24
+ container.appendChild(switchLabelText)
25
+ container.appendChild(checkbox)
26
+ container.appendChild(slider)
27
+
28
+ return { label, checkbox, container }
29
+ }
30
+
5
31
  getSelectInput (options, multiple) {
6
32
  const el = super.getSelectInput(options)
7
33
  el.classList.add('form-control')
@@ -145,6 +171,10 @@ export class bootstrap3Theme extends AbstractTheme {
145
171
  return el
146
172
  }
147
173
 
174
+ getHeaderContainer () {
175
+ return document.createElement('div')
176
+ }
177
+
148
178
  getHeader (text, pathDepth) {
149
179
  const el = document.createElement('span')
150
180
  el.classList.add('h3')
@@ -43,6 +43,33 @@ export class bootstrap4Theme extends AbstractTheme {
43
43
  return el
44
44
  }
45
45
 
46
+ getOptInSwitch (formname) {
47
+ const label = this.getHiddenLabel(formname + ' opt-in')
48
+ label.setAttribute('for', formname + '-opt-in')
49
+
50
+ const container = document.createElement('div')
51
+ container.classList.add('custom-control', 'custom-switch', 'd-inline-block', 'fs-6')
52
+
53
+ const checkbox = document.createElement('input')
54
+ checkbox.setAttribute('type', 'checkbox')
55
+ checkbox.setAttribute('id', formname + '-opt-in')
56
+ checkbox.classList.add('custom-control-input', 'json-editor-opt-in')
57
+
58
+ const switchLabel = document.createElement('label')
59
+ switchLabel.setAttribute('for', formname + '-opt-in')
60
+ switchLabel.classList.add('custom-control-label')
61
+
62
+ const switchLabelText = document.createElement('span')
63
+ switchLabelText.classList.add('sr-only')
64
+ switchLabelText.textContent = formname + '-opt-in'
65
+ switchLabel.appendChild(switchLabelText)
66
+
67
+ container.appendChild(checkbox)
68
+ container.appendChild(switchLabel)
69
+
70
+ return { label, checkbox, container }
71
+ }
72
+
46
73
  setGridColumnSize (el, size, offset) {
47
74
  el.classList.add(`col-md-${size}`)
48
75
 
@@ -35,6 +35,34 @@ export class bootstrap5Theme extends AbstractTheme {
35
35
  return el
36
36
  }
37
37
 
38
+ getOptInSwitch (formname) {
39
+ const label = this.getHiddenLabel(formname + ' opt-in')
40
+ label.setAttribute('for', formname + '-opt-in')
41
+
42
+ const container = document.createElement('div')
43
+ container.classList.add('form-check', 'form-switch', 'd-inline-block', 'fs-6')
44
+
45
+ const checkbox = document.createElement('input')
46
+ checkbox.setAttribute('type', 'checkbox')
47
+ checkbox.setAttribute('role', 'switch')
48
+ checkbox.setAttribute('id', formname + '-opt-in')
49
+ checkbox.classList.add('form-check-input', 'json-editor-opt-in')
50
+
51
+ const switchLabel = document.createElement('label')
52
+ switchLabel.setAttribute('for', formname + '-opt-in')
53
+ switchLabel.classList.add('form-check-label')
54
+
55
+ const switchLabelText = document.createElement('span')
56
+ switchLabelText.classList.add('visually-hidden')
57
+ switchLabelText.textContent = formname + '-opt-in'
58
+ switchLabel.appendChild(switchLabelText)
59
+
60
+ container.appendChild(checkbox)
61
+ container.appendChild(switchLabel)
62
+
63
+ return { label, checkbox, container }
64
+ }
65
+
38
66
  setGridColumnSize (el, size, offset) {
39
67
  el.classList.add(`col-md-${size}`)
40
68
 
@@ -19,6 +19,34 @@ export class spectreTheme extends AbstractTheme {
19
19
  super(jsoneditor, options)
20
20
  }
21
21
 
22
+ getOptInSwitch (formname) {
23
+ const container = document.createElement('span')
24
+ container.classList.add('form-group')
25
+
26
+ const label = document.createElement('label')
27
+ label.classList.add('form-switch', 'd-inline-block')
28
+
29
+ const checkbox = document.createElement('input')
30
+ checkbox.setAttribute('type', 'checkbox')
31
+ checkbox.setAttribute('id', formname + '-opt-in')
32
+ checkbox.classList.add('json-editor-opt-in')
33
+
34
+ const icon = document.createElement('i')
35
+ icon.classList.add('form-icon')
36
+
37
+ const switchLabelText = document.createElement('span')
38
+ switchLabelText.classList.add('sr-only')
39
+ switchLabelText.textContent = formname + '-opt-in'
40
+
41
+ label.appendChild(switchLabelText)
42
+ label.appendChild(checkbox)
43
+ label.appendChild(icon)
44
+
45
+ container.appendChild(label)
46
+
47
+ return { label, checkbox, container }
48
+ }
49
+
22
50
  /* Functions for setting up the grid container, row and columns */
23
51
  setGridColumnSize (el, size, offset) {
24
52
  el.classList.add(`col-${size}`)
@@ -247,3 +247,57 @@ select[multiple].from-select {
247
247
  .je-dropzone.invalid-dropzone {
248
248
  background: red;
249
249
  }
250
+
251
+ .switch {
252
+ position: relative;
253
+ display: inline-block;
254
+ width: 28px;
255
+ height: 16px;
256
+ margin-right: 10px;
257
+ }
258
+
259
+ .switch input {
260
+ opacity: 0;
261
+ width: 0;
262
+ height: 0;
263
+ }
264
+
265
+ .switch-slider {
266
+ position: absolute;
267
+ cursor: pointer;
268
+ top: 0;
269
+ left: 0;
270
+ right: 0;
271
+ bottom: 0;
272
+ background-color: #ccc;
273
+ transition: .1s;
274
+ border-radius: 34px;
275
+ }
276
+
277
+ .switch-slider:before {
278
+ position: absolute;
279
+ content: "";
280
+ height: 12px;
281
+ width: 12px;
282
+ left: 1px;
283
+ top: 2px;
284
+ background-color: white;
285
+ transition: .1s;
286
+ border-radius: 50%;
287
+ }
288
+
289
+ input:checked + .switch-slider {
290
+ background-color: #2196F3;
291
+ }
292
+
293
+ input:focus + .switch-slider {
294
+ box-shadow: 0 0 1px #2196F3;
295
+ }
296
+
297
+ input:checked + .switch-slider:before {
298
+ transform: translateX(12px);
299
+ }
300
+
301
+ input:disabled + .switch-slider {
302
+ opacity: 0.5;
303
+ }
@@ -1,3 +1,3 @@
1
1
  /* eslint-disable */
2
- export default {".slider":"-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;display:block;border:none;height:1.2rem;width:100%25",".slider:focus":"box-shadow:0%200%200%200%20rgba(87%2C%2085%2C%20217%2C%200.2);outline:none",".slider.tooltip:not([data-tooltip])::after":"content:attr(value)",".slider::-webkit-slider-thumb":"-webkit-appearance:none;background:%23f17405;border-radius:100%25;height:0.6rem;margin-top:-0.25rem;transition:transform%200.2s;width:0.6rem",".slider:active::-webkit-slider-thumb":"transform:scale(1.25);outline:none",".slider::-webkit-slider-runnable-track":"background:%23b2b4b6;border-radius:0.1rem;height:0.1rem;width:100%25","a.tooltips":"position:relative;display:inline","a.tooltips span":"position:absolute;white-space:nowrap;width:auto;padding-left:1rem;padding-right:1rem;color:%23ffffff;background:rgba(56%2C%2056%2C%2056%2C%200.85);height:1.5rem;line-height:1.5rem;text-align:center;visibility:hidden;border-radius:3px","a.tooltips span:after":"content:%22%22;position:absolute;top:50%25;left:100%25;margin-top:-5px;width:0;height:0;border-left:5px%20solid%20rgba(56%2C%2056%2C%2056%2C%200.85);border-top:5px%20solid%20transparent;border-bottom:5px%20solid%20transparent","a:hover.tooltips span":"visibility:visible;opacity:0.9;font-size:0.8rem;right:100%25;top:50%25;margin-top:-12px;margin-right:10px;z-index:999",".json-editor-btntype-properties + div":"font-size:0.8rem;font-weight:normal","textarea":"width:100%25;min-height:2rem;resize:vertical","table":"width:100%25;border-collapse:collapse",".table td":"padding:0rem%200rem","div[data-schematype]:not([data-schematype='object'])":"transition:0.5s","div[data-schematype]:not([data-schematype='object']):hover":"background-color:%23e6f4fe","div[data-schemaid='root']":"position:relative;width:inherit;display:inherit;overflow-x:hidden;z-index:10","select[multiple]":"height:auto","select[multiple].from-select":"height:auto",".je-table-zebra:nth-child(even)":"background-color:%23f2f2f2",".je-table-border":"border:0.5px%20solid%20black",".je-table-hdiv":"border-bottom:1px%20solid%20black",".je-border":"border:0.05rem%20solid%20%233182ce",".je-panel":"width:inherit;padding:0.2rem;margin:0.2rem;background-color:rgba(218%2C%20222%2C%20228%2C%200.1)",".je-panel-top":"width:100%25;padding:0.2rem;margin:0.2rem;background-color:rgba(218%2C%20222%2C%20228%2C%200.1)",".required:after":"content:%22%20*%22;color:red;font:inherit;font-weight:bold",".je-desc":"font-size:smaller;margin:0.2rem%200",".container-xl.je-noindent":"padding-left:0;padding-right:0",".json-editor-btntype-add":"color:white;margin:0.3rem;padding:0.3rem%200.8rem;background-color:%234299e1;box-shadow:3px%203px%205px%201px%20rgba(4%2C%204%2C%204%2C%200.2);-webkit-box-shadow:3px%203px%205px%201px%20rgba(4%2C%204%2C%204%2C%200.2);-moz-box-shadow:3px%203px%205px%201px%20rgba(4%2C%204%2C%204%2C%200.2)",".json-editor-btntype-deletelast":"color:white;margin:0.3rem;padding:0.3rem%200.8rem;background-color:%23e53e3e;box-shadow:3px%203px%205px%201px%20rgba(4%2C%204%2C%204%2C%200.2);-webkit-box-shadow:3px%203px%205px%201px%20rgba(4%2C%204%2C%204%2C%200.2);-moz-box-shadow:3px%203px%205px%201px%20rgba(4%2C%204%2C%204%2C%200.2)",".json-editor-btntype-deleteall":"color:white;margin:0.3rem;padding:0.3rem%200.8rem;background-color:%23000000;box-shadow:3px%203px%205px%201px%20rgba(4%2C%204%2C%204%2C%200.2);-webkit-box-shadow:3px%203px%205px%201px%20rgba(4%2C%204%2C%204%2C%200.2);-moz-box-shadow:3px%203px%205px%201px%20rgba(4%2C%204%2C%204%2C%200.2)",".json-editor-btn-save":"float:right;color:white;margin:0.3rem;padding:0.3rem%200.8rem;background-color:%232b6cb0;box-shadow:3px%203px%205px%201px%20rgba(4%2C%204%2C%204%2C%200.2);-webkit-box-shadow:3px%203px%205px%201px%20rgba(4%2C%204%2C%204%2C%200.2);-moz-box-shadow:3px%203px%205px%201px%20rgba(4%2C%204%2C%204%2C%200.2)",".json-editor-btn-back":"color:white;margin:0.3rem;padding:0.3rem%200.8rem;background-color:%232b6cb0;box-shadow:3px%203px%205px%201px%20rgba(4%2C%204%2C%204%2C%200.2);-webkit-box-shadow:3px%203px%205px%201px%20rgba(4%2C%204%2C%204%2C%200.2);-moz-box-shadow:3px%203px%205px%201px%20rgba(4%2C%204%2C%204%2C%200.2)",".json-editor-btntype-delete":"color:%23e53e3e;background-color:rgba(218%2C%20222%2C%20228%2C%200.1);margin:0.03rem;padding:0.1rem",".json-editor-btntype-move":"color:%23000000;background-color:rgba(218%2C%20222%2C%20228%2C%200.1);margin:0.03rem;padding:0.1rem",".json-editor-btn-collapse":"padding:0em%200.8rem;font-size:1.3rem;color:%23e53e3e;background-color:rgba(218%2C%20222%2C%20228%2C%200.1)",".je-upload-preview img":"float:left;margin:0%200.5rem%200.5rem%200;max-width:100%25;max-height:5rem",".je-dropzone":"position:relative;margin:0.5rem%200;border:2px%20dashed%20black;width:100%25;height:60px;background:teal;transition:all%200.5s",".je-dropzone:before":"position:absolute;content:attr(data-text);color:rgba(0%2C%200%2C%200%2C%200.6);left:50%25;top:50%25;transform:translate(-50%25%2C%20-50%25)",".je-dropzone.valid-dropzone":"background:green",".je-dropzone.invalid-dropzone":"background:red"}
2
+ export default {".slider":"-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;display:block;border:none;height:1.2rem;width:100%25",".slider:focus":"box-shadow:0%200%200%200%20rgba(87%2C%2085%2C%20217%2C%200.2);outline:none",".slider.tooltip:not([data-tooltip])::after":"content:attr(value)",".slider::-webkit-slider-thumb":"-webkit-appearance:none;background:%23f17405;border-radius:100%25;height:0.6rem;margin-top:-0.25rem;transition:transform%200.2s;width:0.6rem",".slider:active::-webkit-slider-thumb":"transform:scale(1.25);outline:none",".slider::-webkit-slider-runnable-track":"background:%23b2b4b6;border-radius:0.1rem;height:0.1rem;width:100%25","a.tooltips":"position:relative;display:inline","a.tooltips span":"position:absolute;white-space:nowrap;width:auto;padding-left:1rem;padding-right:1rem;color:%23ffffff;background:rgba(56%2C%2056%2C%2056%2C%200.85);height:1.5rem;line-height:1.5rem;text-align:center;visibility:hidden;border-radius:3px","a.tooltips span:after":"content:%22%22;position:absolute;top:50%25;left:100%25;margin-top:-5px;width:0;height:0;border-left:5px%20solid%20rgba(56%2C%2056%2C%2056%2C%200.85);border-top:5px%20solid%20transparent;border-bottom:5px%20solid%20transparent","a:hover.tooltips span":"visibility:visible;opacity:0.9;font-size:0.8rem;right:100%25;top:50%25;margin-top:-12px;margin-right:10px;z-index:999",".json-editor-btntype-properties + div":"font-size:0.8rem;font-weight:normal","textarea":"width:100%25;min-height:2rem;resize:vertical","table":"width:100%25;border-collapse:collapse",".table td":"padding:0rem%200rem","div[data-schematype]:not([data-schematype='object'])":"transition:0.5s","div[data-schematype]:not([data-schematype='object']):hover":"background-color:%23e6f4fe","div[data-schemaid='root']":"position:relative;width:inherit;display:inherit;overflow-x:hidden;z-index:10","select[multiple]":"height:auto","select[multiple].from-select":"height:auto",".je-table-zebra:nth-child(even)":"background-color:%23f2f2f2",".je-table-border":"border:0.5px%20solid%20black",".je-table-hdiv":"border-bottom:1px%20solid%20black",".je-border":"border:0.05rem%20solid%20%233182ce",".je-panel":"width:inherit;padding:0.2rem;margin:0.2rem;background-color:rgba(218%2C%20222%2C%20228%2C%200.1)",".je-panel-top":"width:100%25;padding:0.2rem;margin:0.2rem;background-color:rgba(218%2C%20222%2C%20228%2C%200.1)",".required:after":"content:%22%20*%22;color:red;font:inherit;font-weight:bold",".je-desc":"font-size:smaller;margin:0.2rem%200",".container-xl.je-noindent":"padding-left:0;padding-right:0",".json-editor-btntype-add":"color:white;margin:0.3rem;padding:0.3rem%200.8rem;background-color:%234299e1;box-shadow:3px%203px%205px%201px%20rgba(4%2C%204%2C%204%2C%200.2);-webkit-box-shadow:3px%203px%205px%201px%20rgba(4%2C%204%2C%204%2C%200.2);-moz-box-shadow:3px%203px%205px%201px%20rgba(4%2C%204%2C%204%2C%200.2)",".json-editor-btntype-deletelast":"color:white;margin:0.3rem;padding:0.3rem%200.8rem;background-color:%23e53e3e;box-shadow:3px%203px%205px%201px%20rgba(4%2C%204%2C%204%2C%200.2);-webkit-box-shadow:3px%203px%205px%201px%20rgba(4%2C%204%2C%204%2C%200.2);-moz-box-shadow:3px%203px%205px%201px%20rgba(4%2C%204%2C%204%2C%200.2)",".json-editor-btntype-deleteall":"color:white;margin:0.3rem;padding:0.3rem%200.8rem;background-color:%23000000;box-shadow:3px%203px%205px%201px%20rgba(4%2C%204%2C%204%2C%200.2);-webkit-box-shadow:3px%203px%205px%201px%20rgba(4%2C%204%2C%204%2C%200.2);-moz-box-shadow:3px%203px%205px%201px%20rgba(4%2C%204%2C%204%2C%200.2)",".json-editor-btn-save":"float:right;color:white;margin:0.3rem;padding:0.3rem%200.8rem;background-color:%232b6cb0;box-shadow:3px%203px%205px%201px%20rgba(4%2C%204%2C%204%2C%200.2);-webkit-box-shadow:3px%203px%205px%201px%20rgba(4%2C%204%2C%204%2C%200.2);-moz-box-shadow:3px%203px%205px%201px%20rgba(4%2C%204%2C%204%2C%200.2)",".json-editor-btn-back":"color:white;margin:0.3rem;padding:0.3rem%200.8rem;background-color:%232b6cb0;box-shadow:3px%203px%205px%201px%20rgba(4%2C%204%2C%204%2C%200.2);-webkit-box-shadow:3px%203px%205px%201px%20rgba(4%2C%204%2C%204%2C%200.2);-moz-box-shadow:3px%203px%205px%201px%20rgba(4%2C%204%2C%204%2C%200.2)",".json-editor-btntype-delete":"color:%23e53e3e;background-color:rgba(218%2C%20222%2C%20228%2C%200.1);margin:0.03rem;padding:0.1rem",".json-editor-btntype-move":"color:%23000000;background-color:rgba(218%2C%20222%2C%20228%2C%200.1);margin:0.03rem;padding:0.1rem",".json-editor-btn-collapse":"padding:0em%200.8rem;font-size:1.3rem;color:%23e53e3e;background-color:rgba(218%2C%20222%2C%20228%2C%200.1)",".je-upload-preview img":"float:left;margin:0%200.5rem%200.5rem%200;max-width:100%25;max-height:5rem",".je-dropzone":"position:relative;margin:0.5rem%200;border:2px%20dashed%20black;width:100%25;height:60px;background:teal;transition:all%200.5s",".je-dropzone:before":"position:absolute;content:attr(data-text);color:rgba(0%2C%200%2C%200%2C%200.6);left:50%25;top:50%25;transform:translate(-50%25%2C%20-50%25)",".je-dropzone.valid-dropzone":"background:green",".je-dropzone.invalid-dropzone":"background:red",".switch":"position:relative;display:inline-block;width:28px;height:16px;margin-right:10px",".switch input":"opacity:0;width:0;height:0",".switch-slider":"position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:%23ccc;transition:.1s;border-radius:34px",".switch-slider:before":"position:absolute;content:%22%22;height:12px;width:12px;left:1px;top:2px;background-color:white;transition:.1s;border-radius:50%25","input:checked + .switch-slider":"background-color:%232196F3","input:focus + .switch-slider":"box-shadow:0%200%201px%20%232196F3","input:checked + .switch-slider:before":"transform:translateX(12px)","input:disabled + .switch-slider":"opacity:0.5"}
3
3
  /* eslint-enable */
@@ -19,6 +19,32 @@ export class tailwindTheme extends AbstractTheme {
19
19
  super(jsoneditor, options)
20
20
  }
21
21
 
22
+ getOptInSwitch (formname) {
23
+ const label = this.getHiddenLabel(formname + ' opt-in')
24
+ label.setAttribute('for', formname + '-opt-in')
25
+
26
+ const container = document.createElement('label')
27
+ container.classList.add('switch')
28
+
29
+ const checkbox = document.createElement('input')
30
+ checkbox.setAttribute('type', 'checkbox')
31
+ checkbox.setAttribute('id', formname + '-opt-in')
32
+ checkbox.classList.add('json-editor-opt-in')
33
+
34
+ const slider = document.createElement('span')
35
+ slider.classList.add('switch-slider', 'round')
36
+
37
+ const switchLabelText = document.createElement('span')
38
+ switchLabelText.classList.add('sr-only')
39
+ switchLabelText.textContent = formname + '-opt-in'
40
+
41
+ container.appendChild(switchLabelText)
42
+ container.appendChild(checkbox)
43
+ container.appendChild(slider)
44
+
45
+ return { label, checkbox, container }
46
+ }
47
+
22
48
  getGridContainer () {
23
49
  const el = document.createElement('div')
24
50
  el.classList.add('flex', 'flex-col', 'w-full')
@@ -5,6 +5,34 @@ const { DEFAULT_WAIT_TIME } = require('./test-config')
5
5
 
6
6
  Feature('core')
7
7
 
8
+ Scenario('should use switch toggles for opt-in inputs @opt-in-widget', async ({ I }) => {
9
+ I.amOnPage('opt-in-widget.html')
10
+ I.waitForElement('.je-ready')
11
+ I.waitForValue('#value', '{}')
12
+ I.click('[data-schemapath="root.address"] .switch-slider')
13
+ I.click('[data-schemapath="root.email"] .switch-slider')
14
+ I.click('[data-schemapath="root.password"] .switch-slider')
15
+ I.click('[data-schemapath="root.name"] .switch-slider')
16
+ I.click('[data-schemapath="root.gender"] .switch-slider')
17
+ I.click('[data-schemapath="root.pets"] .switch-slider')
18
+ I.click('[data-schemapath="root.agree"] .switch-slider')
19
+ I.click('[data-schemapath="root.address.street"] .switch-slider')
20
+ I.click('[data-schemapath="root.address.number"] .switch-slider')
21
+ I.waitForValue('#value', '{"email":"","password":"","name":"Random-223","gender":"Male","address":{"street":"","number":""},"pets":[{"type":"dog","name":"Walter"}],"agree":false}')
22
+ })
23
+
24
+ Scenario('should show all validation errors on demand @editor-show-validation-errors', async ({ I }) => {
25
+ I.amOnPage('editor-show-validation-errors.html')
26
+ I.waitForElement('.je-ready')
27
+ I.dontSee('Value must be the constant value')
28
+ I.dontSee('Value must be at least 4 characters long')
29
+ I.dontSee('Value must be at least 4')
30
+ I.click('#show-validation-errors')
31
+ I.waitForText('Value must be the constant value')
32
+ I.waitForText('Value must be at least 4 characters long')
33
+ I.waitForText('Value must be at least 4')
34
+ })
35
+
8
36
  Scenario('should enforce const @enforce_const', async ({ I }) => {
9
37
  I.amOnPage('enforce-const.html')
10
38
  I.waitForElement('.je-ready')
@@ -0,0 +1,27 @@
1
+ /* global Feature Scenario Event */
2
+
3
+ const { DEFAULT_WAIT_TIME } = require('../test-config')
4
+
5
+ Feature('multiple')
6
+
7
+ Scenario('should hide switcher input @switcher-option', async ({ I }) => {
8
+ I.amOnPage('switcher-option.html')
9
+ I.waitForElement('.je-ready')
10
+ I.dontSeeElement('.je-switcher')
11
+
12
+ I.fillField('[name="root[name]"]', 'a')
13
+ I.pressKey('Tab')
14
+ I.waitForText('If provided, value must be at least 4 and at most 10')
15
+
16
+ I.fillField('[name="root[name]"]', '')
17
+ I.pressKey('Tab')
18
+ I.dontSee('If provided, value must be at least 4 and at most 10')
19
+
20
+ I.fillField('[name="root[name]"]', 'abcdefghijklmnopq')
21
+ I.pressKey('Tab')
22
+ I.waitForText('If provided, value must be at least 4 and at most 10')
23
+
24
+ I.fillField('[name="root[name]"]', 'test')
25
+ I.pressKey('Tab')
26
+ I.dontSee('If provided, value must be at least 4 and at most 10')
27
+ })
@@ -0,0 +1,15 @@
1
+ /* global Feature Scenario */
2
+
3
+ Feature('issues')
4
+
5
+ Scenario('GitHub issue 1559 should remain fixed @issue-1559', async ({ I }) => {
6
+ I.amOnPage('issues/issue-gh-1559.html')
7
+ I.waitForElement('.je-ready')
8
+ I.dontSeeElement('[data-schemapath="root.dependent_on_false"]')
9
+ I.click('[data-schemapath="root.dependent_on_true"] input')
10
+ I.waitForElement('[data-schemapath="root.dependent_on_false"]', 2)
11
+ I.seeElement('[data-schemapath="root.dependent_on_false"]')
12
+ I.click('[data-schemapath="root.dependent_on_true"] input')
13
+ I.waitForInvisible('[data-schemapath="root.dependent_on_false"]', 2)
14
+ I.dontSeeElement('[data-schemapath="root.dependent_on_false"]')
15
+ })
@@ -0,0 +1,12 @@
1
+ /* global Feature Scenario */
2
+
3
+ Feature('issues')
4
+
5
+ Scenario('GitHub issue 1562 should remain fixed @issue-1562', async ({ I }) => {
6
+ I.amOnPage('issues/issue-gh-1562.html')
7
+ I.waitForElement('.je-ready')
8
+ I.click('#editor-container > div > div.card.card-body.mb-3.bg-light > div > div > div > div > div.card.card-body.mb-3.bg-light > div > div > div:nth-child(2) > div > span.btn-group.je-object__controls > button.btn.btn-secondary.btn-sm.json-editor-btn-edit_properties.json-editor-btntype-properties')
9
+ I.fillField('[id="root.model.entities-property-selector"]', 'test')
10
+ I.click('#editor-container > div > div.card.card-body.mb-3.bg-light > div > div > div > div > div.card.card-body.mb-3.bg-light > div > div > div:nth-child(2) > div > span.btn-group.je-object__controls > div:nth-child(2) > button')
11
+ I.waitForText('Expand')
12
+ })
@@ -0,0 +1,15 @@
1
+ /* global Feature Scenario */
2
+
3
+ Feature('issues')
4
+
5
+ Scenario('GitHub issue 1586 should remain fixed @issue-1586', async ({ I }) => {
6
+ I.amOnPage('issues/issue-gh-1586.html')
7
+ I.waitForElement('.je-ready')
8
+ I.click({ xpath: '//button[contains(@class, "json-editor-btn-add") and .//span[contains(text(), "Add item")]]' })
9
+ I.checkOption('[id="root[0][type]-opt-in"]')
10
+ I.checkOption('[id="root[0][subtype][type]-opt-in"]')
11
+ I.click('.json-editor-btn-delete')
12
+ I.click({ xpath: '//button[contains(@class, "json-editor-btn-add") and .//span[contains(text(), "Add item")]]' })
13
+ I.seeDisabledAttribute('[id="root[0][type]"]')
14
+ I.seeDisabledAttribute('[id="root[0][subtype][type]"]')
15
+ })
@@ -0,0 +1,54 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8"/>
5
+ <title>showValidationErrors</title>
6
+ <script src="../../dist/jsoneditor.js"></script>
7
+ <link rel="stylesheet" id="theme-link" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
8
+ <link rel="stylesheet" id="iconlib-link" href="https://use.fontawesome.com/releases/v5.6.1/css/all.css">
9
+ </head>
10
+ <body>
11
+
12
+ <div class="container">
13
+ <div id='editor-container'></div>
14
+ <div class="btn btn-success" id="show-validation-errors">Show validation errors</div>
15
+ </div>
16
+
17
+ <script>
18
+ const editorContainer = document.querySelector('#editor-container')
19
+ const schema = {
20
+ "type": "object",
21
+ "properties": {
22
+ "boolean-checkbox": {
23
+ "title": "boolean-checkbox",
24
+ "type": "boolean",
25
+ "format": "checkbox",
26
+ "const": true,
27
+ "default": false
28
+ },
29
+ "minLength": {
30
+ "type": "string",
31
+ "minLength": 4,
32
+ },
33
+ "minimum": {
34
+ "type": "number",
35
+ "minimum": 4,
36
+ }
37
+ }
38
+ }
39
+
40
+ const editor = new JSONEditor(editorContainer, {
41
+ schema: schema,
42
+ theme: 'bootstrap4',
43
+ iconlib: 'fontawesome'
44
+ })
45
+
46
+ const showValidationErrors = document.querySelector('#show-validation-errors')
47
+
48
+ showValidationErrors.addEventListener('click', () => {
49
+ editor.showValidationErrors()
50
+ })
51
+ </script>
52
+
53
+ </body>
54
+ </html>