@json-editor/json-editor 2.15.0 → 2.15.2

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 +0 -4
  2. package/.github/workflows/build.yml +5 -5
  3. package/CHANGELOG.md +19 -0
  4. package/README.md +16 -0
  5. package/config/codeceptjs_helpers.js +11 -0
  6. package/dist/jsoneditor.js +1 -1
  7. package/dist/jsoneditor.js.LICENSE.txt +1 -1
  8. package/dist/nonmin/jsoneditor.js +502 -152
  9. package/dist/nonmin/jsoneditor.js.map +1 -1
  10. package/package.json +1 -1
  11. package/src/core.js +11 -0
  12. package/src/defaults.js +2 -1
  13. package/src/editor.js +26 -15
  14. package/src/editors/ace.js +1 -0
  15. package/src/editors/array/choices.js +1 -0
  16. package/src/editors/array/select2.js +2 -0
  17. package/src/editors/array/selectize.js +2 -0
  18. package/src/editors/array.js +81 -0
  19. package/src/editors/base64.js +2 -0
  20. package/src/editors/checkbox.js +13 -1
  21. package/src/editors/choices.js +2 -0
  22. package/src/editors/colorpicker.js +2 -0
  23. package/src/editors/datetime.js +2 -0
  24. package/src/editors/describedby.js +2 -0
  25. package/src/editors/enum.js +3 -1
  26. package/src/editors/hidden.js +2 -0
  27. package/src/editors/jodit.js +2 -0
  28. package/src/editors/multiple.js +2 -0
  29. package/src/editors/multiselect.js +2 -0
  30. package/src/editors/object.js +10 -3
  31. package/src/editors/radio.js +2 -0
  32. package/src/editors/sceditor.js +2 -0
  33. package/src/editors/select.js +9 -4
  34. package/src/editors/select2.js +2 -0
  35. package/src/editors/selectize.js +2 -0
  36. package/src/editors/signature.js +2 -0
  37. package/src/editors/simplemde.js +3 -1
  38. package/src/editors/starrating.js +2 -0
  39. package/src/editors/string.js +2 -0
  40. package/src/editors/table.js +19 -2
  41. package/src/editors/upload.js +2 -0
  42. package/src/editors/uuid.js +2 -0
  43. package/src/resolvers.js +1 -1
  44. package/src/theme.js +23 -0
  45. package/src/themes/bootstrap3.css +53 -0
  46. package/src/themes/bootstrap3.css.js +1 -1
  47. package/src/themes/bootstrap3.js +30 -0
  48. package/src/themes/bootstrap4.js +27 -0
  49. package/src/themes/bootstrap5.js +28 -0
  50. package/src/themes/spectre.js +28 -0
  51. package/src/themes/tailwind.css +54 -0
  52. package/src/themes/tailwind.css.js +1 -1
  53. package/src/themes/tailwind.js +26 -0
  54. package/tests/codeceptjs/core_test.js +28 -0
  55. package/tests/codeceptjs/editors/integer_test.js +3 -1
  56. package/tests/codeceptjs/editors/multiple_test.js +27 -0
  57. package/tests/codeceptjs/editors/select_test.js +12 -0
  58. package/tests/codeceptjs/issues/issue-gh-1562_test.js +12 -0
  59. package/tests/codeceptjs/issues/issue-gh-1586_test.js +15 -0
  60. package/tests/docker-compose-local.yml +2 -1
  61. package/tests/pages/editor-show-validation-errors.html +54 -0
  62. package/tests/pages/enforce-const.html +10 -18
  63. package/tests/pages/integer.html +9 -10
  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/select-values.html +91 -0
  68. package/tests/pages/switcher-option.html +69 -0
@@ -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')
@@ -69,10 +69,12 @@ Scenario('should be readonly if specified and not disabled @readOnly', async ({
69
69
  I.seeReadOnlyAttribute('[name="root[integer]"]')
70
70
  })
71
71
 
72
- Scenario('should update output when (method) setValue is called', async ({ I }) => {
72
+ Scenario('should update output when (method) setValue is called @integer_range', async ({ I }) => {
73
73
  I.amOnPage('integer.html')
74
+ I.waitForElement('.je-ready')
74
75
  I.waitForText('5', DEFAULT_WAIT_TIME, '[data-schemapath="root.integer_range"] output')
75
76
  I.click('.set-value')
77
+ I.wait(1)
76
78
  I.waitForText('2', DEFAULT_WAIT_TIME, '[data-schemapath="root.integer_range"] output')
77
79
  })
78
80
 
@@ -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
+ })
@@ -2,6 +2,18 @@
2
2
 
3
3
  Feature('select')
4
4
 
5
+ Scenario('Should start with correct value @select-value', async ({ I }) => {
6
+ I.amOnPage('select-values.html')
7
+ I.waitForElement('.je-ready')
8
+ I.waitForValue('#value', '{"data":[]}')
9
+ I.click('#set-value')
10
+ I.waitForValue('#value', '{"data":[{"baumart":"other_hardwood"},{"baumart":"beech"},{"baumart":"oak"},{"baumart":"spruce"}]}')
11
+ I.getSelectedValueAndAssert('select[name="root[data][0][baumart]"]', 'other_hardwood');
12
+ I.getSelectedValueAndAssert('select[name="root[data][1][baumart]"]', 'beech');
13
+ I.getSelectedValueAndAssert('select[name="root[data][2][baumart]"]', 'oak');
14
+ I.getSelectedValueAndAssert('select[name="root[data][3][baumart]"]', 'spruce');
15
+ })
16
+
5
17
  Scenario('Should render a non selectable placeholder options for not in enum values @placeholderOption', async ({ I }) => {
6
18
  I.amOnPage('placeholder-options.html')
7
19
  I.waitForElement('.je-ready')
@@ -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
+ })
@@ -1,3 +1,4 @@
1
+ version: '3'
1
2
  services:
2
3
  chrome:
3
- image: seleniarm/standalone-chromium:114.0
4
+ image: seleniarm/standalone-chromium:114.0
@@ -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>