@json-editor/json-editor 2.11.0 → 2.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/.env +1 -1
  2. package/CHANGELOG.md +11 -0
  3. package/README.md +77 -1
  4. package/README_ADDON.md +5 -1
  5. package/dist/jsoneditor.js +1 -1
  6. package/dist/jsoneditor.js.LICENSE.txt +1 -1
  7. package/dist/nonmin/jsoneditor.js +330 -169
  8. package/dist/nonmin/jsoneditor.js.map +1 -1
  9. package/docs/cleave.html +1 -1
  10. package/docs/datetime.html +1 -1
  11. package/docs/describedby.html +1 -1
  12. package/docs/index.html +5 -3
  13. package/docs/meta_schema.json +5 -1
  14. package/docs/radio.html +1 -1
  15. package/docs/select2.html +1 -1
  16. package/docs/selectize.html +2 -5
  17. package/docs/signature.html +12 -11
  18. package/docs/wysiwyg.html +1 -1
  19. package/package.json +1 -1
  20. package/src/core.js +10 -1
  21. package/src/defaults.js +3 -1
  22. package/src/editor.js +1 -1
  23. package/src/editors/array/selectize.js +0 -2
  24. package/src/editors/array.js +24 -13
  25. package/src/editors/base64.js +9 -0
  26. package/src/editors/integer.js +3 -2
  27. package/src/editors/multiple.js +3 -0
  28. package/src/editors/number.js +4 -2
  29. package/src/editors/object.js +71 -3
  30. package/src/editors/signature.js +16 -16
  31. package/src/editors/string.js +4 -0
  32. package/src/editors/table.js +17 -14
  33. package/src/resolvers.js +6 -2
  34. package/src/schemaloader.js +13 -0
  35. package/src/theme.js +4 -0
  36. package/src/themes/bootstrap3.js +6 -0
  37. package/src/themes/bootstrap4.js +6 -0
  38. package/src/themes/bootstrap5.js +6 -0
  39. package/src/validator.js +28 -0
  40. package/tests/codeceptjs/constrains/dependentRequired_test.js +33 -0
  41. package/tests/codeceptjs/core_test.js +10 -0
  42. package/tests/codeceptjs/editors/array_test.js +52 -0
  43. package/tests/codeceptjs/editors/object_test.js +20 -0
  44. package/tests/codeceptjs/issues/issue-gh-1330_test.js +8 -0
  45. package/tests/codeceptjs/issues/issue-gh-1338_test.js +2 -0
  46. package/tests/codeceptjs/issues/issue-gh-1364_test.js +13 -0
  47. package/tests/codeceptjs/issues/issue-gh-1367_test.js +11 -0
  48. package/tests/codeceptjs/issues/issue-gh-1383_test.js +9 -0
  49. package/tests/codeceptjs/issues/issue-gh-1384_test.js +9 -0
  50. package/tests/codeceptjs/issues/issue-gh-1410_test.js +13 -0
  51. package/tests/codeceptjs/issues/issue-gh-1422_test.js +9 -0
  52. package/tests/docker-compose-local.yml +4 -0
  53. package/tests/pages/array-selectize-create.html +62 -0
  54. package/tests/pages/array-table-responsive.html +65 -0
  55. package/tests/pages/button_state_mode_1.html +34 -0
  56. package/tests/pages/button_state_mode_2.html +35 -0
  57. package/tests/pages/dependentRequired.html +71 -0
  58. package/tests/pages/issues/issue-gh-1330.html +52 -0
  59. package/tests/pages/issues/issue-gh-1364.html +64 -0
  60. package/tests/pages/issues/issue-gh-1367.html +49 -0
  61. package/tests/pages/issues/issue-gh-1383.html +31 -0
  62. package/tests/pages/issues/issue-gh-1383.json +14 -0
  63. package/tests/pages/issues/issue-gh-1384.html +31 -0
  64. package/tests/pages/issues/issue-gh-1384.json +36 -0
  65. package/tests/pages/issues/issue-gh-1410.html +57 -0
  66. package/tests/pages/issues/issue-gh-1422.html +68 -0
  67. package/tests/pages/keep_only_existing_values.html +1 -1
  68. package/tests/pages/load-events.html +60 -0
  69. package/tests/pages/meta-schema.html +5 -1
  70. package/tests/pages/meta_schema.json +5 -1
  71. package/tests/pages/object-case-sensitive-property-search-false.html +41 -0
  72. package/tests/pages/object-case-sensitive-property-search-true.html +41 -0
  73. package/dist/dev/jsoneditor.js +0 -3687
  74. package/dist/jsoneditor.js.map +0 -1
@@ -36,8 +36,11 @@ export class TableEditor extends ArrayEditor {
36
36
  }
37
37
 
38
38
  build () {
39
+ this.tableContainer = this.theme.getTableContainer()
39
40
  this.table = this.theme.getTable()
40
- this.container.appendChild(this.table)
41
+ this.tableContainer.appendChild(this.table)
42
+
43
+ this.container.appendChild(this.tableContainer)
41
44
  this.thead = this.theme.getTableHead()
42
45
  this.table.appendChild(this.thead)
43
46
  this.header_row = this.theme.getTableRow()
@@ -74,7 +77,7 @@ export class TableEditor extends ArrayEditor {
74
77
  this.container.appendChild(this.panel)
75
78
  }
76
79
 
77
- this.panel.appendChild(this.table)
80
+ this.panel.appendChild(this.tableContainer)
78
81
  this.controls = this.theme.getButtonHolder()
79
82
  if (this.array_controls_top) {
80
83
  this.title.appendChild(this.controls)
@@ -232,28 +235,28 @@ export class TableEditor extends ArrayEditor {
232
235
  if (editor.delete_button) {
233
236
  /* Hide the delete button if we have minItems items */
234
237
  const display = !minItems
235
- this.setVisibility(editor.delete_button, display)
238
+ this.setButtonState(editor.delete_button, display)
236
239
  needRowButtons.push(display)
237
240
  }
238
241
 
239
242
  if (editor.copy_button) {
240
243
  /* Hide the copy button if we have maxItems items */
241
244
  const display = !maxItems
242
- this.setVisibility(editor.copy_button, display)
245
+ this.setButtonState(editor.copy_button, display)
243
246
  needRowButtons.push(display)
244
247
  }
245
248
 
246
249
  if (editor.moveup_button) {
247
250
  /* Hide the moveup button for the first row */
248
251
  const display = i !== 0
249
- this.setVisibility(editor.moveup_button, display)
252
+ this.setButtonState(editor.moveup_button, display)
250
253
  needRowButtons.push(display)
251
254
  }
252
255
 
253
256
  if (editor.movedown_button) {
254
257
  /* Hide the movedown button for the last row */
255
258
  const display = i !== this.rows.length - 1
256
- this.setVisibility(editor.movedown_button, display)
259
+ this.setButtonState(editor.movedown_button, display)
257
260
  needRowButtons.push(display)
258
261
  }
259
262
  })
@@ -261,26 +264,26 @@ export class TableEditor extends ArrayEditor {
261
264
  const need = needRowButtons.some(e => e)
262
265
  /* Show/hide controls column in table */
263
266
  this.rows.forEach((editor) =>
264
- this.setVisibility(editor.controls_cell, need)
267
+ this.setButtonState(editor.controls_cell, need)
265
268
  )
266
- this.setVisibility(this.controls_header_cell, need)
269
+ this.setButtonState(this.controls_header_cell, need)
267
270
 
268
- this.setVisibility(this.table, this.value.length)
271
+ this.setButtonState(this.table, this.value.length)
269
272
 
270
273
  /* If there are maxItems items in the array, or configured to hide the add_row_button button, hide the button beneath the rows */
271
274
  const display1 = !(maxItems || this.hide_add_button)
272
- this.setVisibility(this.add_row_button, display1)
275
+ this.setButtonState(this.add_row_button, display1)
273
276
 
274
277
  /* If there are minItems items in the array, or configured to hide the delete_last_row button, hide the button beneath the rows */
275
278
  const display2 = !(!this.value.length || minItems || this.hide_delete_last_row_buttons)
276
- this.setVisibility(this.delete_last_row_button, display2)
279
+ this.setButtonState(this.delete_last_row_button, display2)
277
280
 
278
281
  /* If there are minItems items in the array, or configured to hide the remove_all_rows_button button, hide the button beneath the rows */
279
282
  const display3 = !(this.value.length <= 1 || minItems || this.hide_delete_all_rows_buttons)
280
- this.setVisibility(this.remove_all_rows_button, display3)
283
+ this.setButtonState(this.remove_all_rows_button, display3)
281
284
 
282
285
  const controlsNeeded = display1 || display2 || display3
283
- this.setVisibility(this.controls, controlsNeeded)
286
+ this.setButtonState(this.controls, controlsNeeded)
284
287
  }
285
288
 
286
289
  refreshValue () {
@@ -439,7 +442,7 @@ export class TableEditor extends ArrayEditor {
439
442
  e.preventDefault()
440
443
  e.stopPropagation()
441
444
 
442
- this.setVisibility(this.panel, this.collapsed)
445
+ this.setButtonState(this.panel, this.collapsed)
443
446
  if (this.collapsed) {
444
447
  this.collapsed = false
445
448
  this.setButtonText(e.currentTarget, '', 'collapse', 'button_collapse')
package/src/resolvers.js CHANGED
@@ -61,7 +61,11 @@ const enumeratedProperties = schema => {
61
61
  }
62
62
 
63
63
  /* Specialized editors for arrays of strings */
64
- const arraysOfStrings = schema => {
64
+ const arraysOfStrings = (schema, je) => {
65
+ if (schema.items) {
66
+ schema.items = je.expandSchema(schema.items)
67
+ }
68
+
65
69
  if (schema.type === 'array' && schema.items && !(Array.isArray(schema.items)) && ['string', 'number', 'integer'].includes(schema.items.type)) {
66
70
  if (schema.format === 'choices') return 'arrayChoices'
67
71
  if (schema.uniqueItems) {
@@ -117,7 +121,7 @@ const markdown = schema => schema.type === 'string' && schema.format === 'markdo
117
121
  const xhtml = schema => schema.type === 'string' && ['xhtml', 'bbcode'].includes(schema.format) && 'sceditor'
118
122
 
119
123
  /* Use the ace editor for schemas with format equals any of ace editor modes */
120
- const aceModes = ['actionscript', 'batchfile', 'c', 'c++', 'cpp', 'coffee', 'csharp', 'css', 'dart', 'django', 'ejs', 'erlang', 'golang', 'groovy', 'handlebars', 'haskell', 'haxe', 'html', 'ini', 'jade', 'java', 'javascript', 'json', 'less', 'lisp', 'lua', 'makefile', 'matlab', 'mysql', 'objectivec', 'pascal', 'perl', 'pgsql', 'php', 'python', 'r', 'ruby', 'sass', 'scala', 'scss', 'sh', 'smarty', 'sql', 'sqlserver', 'stylus', 'svg', 'twig', 'vbscript', 'xml', 'yaml']
124
+ const aceModes = ['actionscript', 'batchfile', 'c', 'c++', 'cpp', 'coffee', 'csharp', 'css', 'dart', 'django', 'ejs', 'erlang', 'golang', 'groovy', 'handlebars', 'haskell', 'haxe', 'html', 'ini', 'jade', 'java', 'javascript', 'json', 'less', 'lisp', 'lua', 'makefile', 'matlab', 'mysql', 'objectivec', 'pascal', 'perl', 'pgsql', 'php', 'python', 'prql', 'r', 'ruby', 'rust', 'sass', 'scala', 'scss', 'sh', 'smarty', 'sql', 'sqlserver', 'stylus', 'svg', 'typescript', 'twig', 'vbscript', 'xml', 'yaml', 'zig']
121
125
  const ace = schema => schema.type === 'string' && aceModes.includes(schema.format) && 'ace'
122
126
 
123
127
  const ip = schema => schema.type === 'string' && ['ip', 'ipv4', 'ipv6', 'hostname'].includes(schema.format) && 'ip'
@@ -449,6 +449,12 @@ export class SchemaLoader {
449
449
  if (typeof response === 'undefined') throw new Error(`Failed to fetch ref via ajax - ${uri}`)
450
450
  try {
451
451
  externalSchema = JSON.parse(response.responseText)
452
+
453
+ this.onSchemaLoaded({
454
+ schema: externalSchema,
455
+ schemaUrl: url
456
+ })
457
+
452
458
  if (this.options.ajax_cache_responses) {
453
459
  this.cacheSet(url, externalSchema)
454
460
  }
@@ -472,11 +478,18 @@ export class SchemaLoader {
472
478
  }
473
479
  await this._asyncloadExternalRefs(externalSchema, url, newfileBase)
474
480
  }
481
+
475
482
  if (!waiting) {
476
483
  return true
477
484
  }
485
+
486
+ this.onAllSchemasLoaded()
478
487
  }
479
488
 
489
+ onSchemaLoaded (payload) {}
490
+
491
+ onAllSchemasLoaded () {}
492
+
480
493
  extendSchemas (obj1, obj2) {
481
494
  obj1 = extend({}, obj1)
482
495
  obj2 = extend({}, obj2)
package/src/theme.js CHANGED
@@ -414,6 +414,10 @@ export class AbstractTheme {
414
414
  if (title) button.setAttribute('title', title)
415
415
  }
416
416
 
417
+ getTableContainer () {
418
+ return document.createElement('div')
419
+ }
420
+
417
421
  /* Table functions */
418
422
  getTable () {
419
423
  return document.createElement('table')
@@ -136,6 +136,12 @@ export class bootstrap3Theme extends AbstractTheme {
136
136
  return el
137
137
  }
138
138
 
139
+ getTableContainer () {
140
+ const el = super.getTableContainer()
141
+ el.classList.add('table-responsive')
142
+ return el
143
+ }
144
+
139
145
  getTable () {
140
146
  const el = document.createElement('table')
141
147
  el.classList.add('table', 'table-bordered')
@@ -454,6 +454,12 @@ export class bootstrap4Theme extends AbstractTheme {
454
454
  return el
455
455
  }
456
456
 
457
+ getTableContainer () {
458
+ const el = super.getTableContainer()
459
+ el.classList.add('table-responsive')
460
+ return el
461
+ }
462
+
457
463
  getTable () {
458
464
  const el = document.createElement('table')
459
465
  el.classList.add('table', 'table-sm')
@@ -390,6 +390,12 @@ export class bootstrap5Theme extends AbstractTheme {
390
390
  return el
391
391
  }
392
392
 
393
+ getTableContainer () {
394
+ const el = super.getTableContainer()
395
+ el.classList.add('table-responsive')
396
+ return el
397
+ }
398
+
393
399
  getTable () {
394
400
  const el = document.createElement('table')
395
401
  el.classList.add('table', 'table-sm')
package/src/validator.js CHANGED
@@ -11,6 +11,34 @@ export class Validator {
11
11
  this.defaults = defaults
12
12
 
13
13
  this._validateSubSchema = {
14
+ dependentRequired (schema, value, path) {
15
+ const errors = []
16
+
17
+ if (typeof schema.dependentRequired !== 'undefined') {
18
+ let missingProperties = []
19
+
20
+ Object.keys(schema.dependentRequired).forEach((key) => {
21
+ if (typeof value[key] !== 'undefined') {
22
+ const requiredProperties = schema.dependentRequired[key]
23
+
24
+ missingProperties = requiredProperties.filter((property) => {
25
+ return !hasOwnProperty(value, property)
26
+ })
27
+ }
28
+ })
29
+
30
+ const invalid = missingProperties.length > 0
31
+
32
+ if (invalid) {
33
+ errors.push({
34
+ message: 'Must have the required properties: ' + missingProperties.join(', '),
35
+ path: path
36
+ })
37
+ }
38
+ }
39
+
40
+ return errors
41
+ },
14
42
  dependentSchemas (schema, value, path) {
15
43
  let errors = []
16
44
 
@@ -0,0 +1,33 @@
1
+ /* global Feature Scenario */
2
+
3
+ Feature('dependentRequired')
4
+
5
+ Scenario('@dependentRequired should display validation errors', ({ I }) => {
6
+ I.amOnPage('dependentRequired.html')
7
+ I.waitForElement('.je-ready')
8
+ I.waitForValue('#textarea-value', '{"name":""}')
9
+
10
+ I.click('[data-schemapath="root.credit_card"] .json-editor-opt-in')
11
+ I.waitForValue('#textarea-value', '{"name":"","credit_card":0,"billing_address_1":"","billing_address_2":""}')
12
+ I.waitForText('Must have the required properties: billing_address_3')
13
+
14
+ I.click('[data-schemapath="root.billing_address_1"] .json-editor-opt-in')
15
+ I.waitForValue('#textarea-value', '{"name":"","credit_card":0,"billing_address_1":"","billing_address_2":""}')
16
+ I.waitForText('Must have the required properties: billing_address_3')
17
+
18
+ I.click('[data-schemapath="root.billing_address_2"] .json-editor-opt-in')
19
+ I.waitForValue('#textarea-value', '{"name":"","credit_card":0,"billing_address_1":"","billing_address_2":""}')
20
+ I.waitForText('Must have the required properties: billing_address_3')
21
+
22
+ I.click('[data-schemapath="root.credit_card"] .json-editor-opt-in')
23
+ I.waitForValue('#textarea-value', '{"name":"","billing_address_1":"","billing_address_2":""}')
24
+ I.waitForText('Must have the required properties: billing_address_3')
25
+
26
+ I.click('[data-schemapath="root.billing_address_1"] .json-editor-opt-in')
27
+ I.waitForValue('#textarea-value', '{"name":"","billing_address_2":""}')
28
+ I.waitForText('Must have the required properties: billing_address_3')
29
+
30
+ I.click('[data-schemapath="root.billing_address_2"] .json-editor-opt-in')
31
+ I.waitForValue('#textarea-value', '{"name":""}')
32
+ I.dontSee('Must have the required properties: billing_address_3')
33
+ })
@@ -5,6 +5,16 @@ const { DEFAULT_WAIT_TIME } = require('./test-config')
5
5
 
6
6
  Feature('core')
7
7
 
8
+ Scenario('should listen to @load-events', async ({ I }) => {
9
+ I.amOnPage('load-events.html')
10
+ I.waitForElement('.je-ready')
11
+ I.waitForText('/tests/pages/../fixtures/basic_person.json')
12
+ I.waitForText('{"title":"Person","type":"object","id":"person","properties":{"name":{"type":"string","description":"First and Last name","minLength":4},"age":{"type":"integer","default":21,"minimum":18,"maximum":99},"gender":{"type":"string","enum":["male","female","other"]}}}')
13
+ I.waitForText('/tests/pages/../fixtures/person.json')
14
+ I.waitForText('{"$ref":"../fixtures/basic_person.json","properties":{"location":{"type":"object","title":"Location","properties":{"city":{"type":"string"},"state":{"type":"string"},"citystate":{"type":"string","description":"This is generated automatically from the previous two fields","template":"{{city}}, {{state}}","watch":{"city":"person.location.city","state":"person.location.state"}}}},"pets":{"type":"array","format":"table","title":"Pets","uniqueItems":true,"items":{"type":"object","properties":{"type":{"type":"string","enum":["cat","dog","bird","reptile","other"],"default":"dog"},"name":{"type":"string"},"fixed":{"type":"boolean","title":"spayed / neutered"}}}}}}')
15
+ I.waitForText('All schemas loaded')
16
+ })
17
+
8
18
  Scenario('should set per-editor options @per-editor-options', async ({ I }) => {
9
19
  I.amOnPage('per-editor-options.html')
10
20
  I.waitForElement('.je-ready')
@@ -4,6 +4,36 @@ const { DEFAULT_WAIT_TIME } = require('../test-config')
4
4
 
5
5
  Feature('array')
6
6
 
7
+ Scenario('Should set buttons states correctly @button_state_mode', async ({ I }) => {
8
+ I.amOnPage('button_state_mode_1.html')
9
+ I.waitForElement('.je-ready', DEFAULT_WAIT_TIME)
10
+ I.waitForElement('.json-editor-btntype-add', DEFAULT_WAIT_TIME)
11
+ I.waitForElement('.json-editor-btn-movedown', DEFAULT_WAIT_TIME)
12
+ I.waitForElement('.json-editor-btn-moveup', DEFAULT_WAIT_TIME)
13
+ I.dontSeeElement('.json-editor-btntype-delete')
14
+ I.dontSeeElement('.json-editor-btntype-deletelast')
15
+ I.dontSeeElement('.json-editor-btntype-deleteall')
16
+ I.click('.json-editor-btntype-add')
17
+ I.waitForElement('.json-editor-btntype-delete')
18
+ I.waitForElement('.json-editor-btntype-deletelast')
19
+ I.waitForElement('.json-editor-btntype-deleteall')
20
+
21
+ I.amOnPage('button_state_mode_2.html')
22
+ I.waitForElement('.je-ready', DEFAULT_WAIT_TIME)
23
+ I.waitForElement('.json-editor-btntype-add', DEFAULT_WAIT_TIME)
24
+ I.waitForElement('.json-editor-btn-movedown', DEFAULT_WAIT_TIME)
25
+ I.waitForElement('.json-editor-btn-moveup', DEFAULT_WAIT_TIME)
26
+ I.waitForElement('.json-editor-btntype-delete', DEFAULT_WAIT_TIME)
27
+ I.waitForElement('.json-editor-btntype-deletelast', DEFAULT_WAIT_TIME)
28
+ I.seeDisabledAttribute('.json-editor-btntype-delete')
29
+ I.seeDisabledAttribute('.json-editor-btntype-deletelast')
30
+ I.seeDisabledAttribute('.json-editor-btntype-deleteall')
31
+ I.click('.json-editor-btntype-add')
32
+ I.dontSeeDisabledAttribute('.json-editor-btntype-delete')
33
+ I.dontSeeDisabledAttribute('.json-editor-btntype-deletelast')
34
+ I.dontSeeDisabledAttribute('.json-editor-btntype-deleteall')
35
+ })
36
+
7
37
  Scenario('should have correct initial value', async ({ I }) => {
8
38
  I.amOnPage('array.html')
9
39
  I.click('.get-value')
@@ -963,3 +993,25 @@ Scenario('should work well with selectize multiselect editors', async ({ I }) =>
963
993
  I.seeElement('[data-schemapath="root.0"] .selectize-dropdown-content [data-value="3"]')
964
994
  I.seeElement('[data-schemapath="root.0"] .selectize-dropdown-content [data-value="4"]')
965
995
  })
996
+
997
+ Scenario('should be possible to add items to selectize array @selectize-add', async ({ I }) => {
998
+ I.amOnPage('array-selectize-create.html')
999
+ I.click('.selectize-input')
1000
+ I.pressKey('g')
1001
+ I.pressKey('Enter')
1002
+ I.pressKey('r')
1003
+ I.pressKey('Enter')
1004
+ I.pressKey('e')
1005
+ I.pressKey('Enter')
1006
+ I.pressKey('a')
1007
+ I.pressKey('Enter')
1008
+ I.pressKey('t')
1009
+ I.pressKey('Enter')
1010
+ I.waitForValue('#value', '["g","r","e","a","t"]')
1011
+ })
1012
+
1013
+ Scenario('Tables should have a container parent that makes tables responsive @array-table', async ({ I }) => {
1014
+ I.amOnPage('array-table-responsive.html')
1015
+ I.waitForElement('.je-ready', DEFAULT_WAIT_TIME)
1016
+ I.waitForElement('.table-responsive')
1017
+ })
@@ -5,6 +5,26 @@ const { DEFAULT_WAIT_TIME } = require('../test-config')
5
5
 
6
6
  Feature('object')
7
7
 
8
+ Scenario('@case-sensitive-property-search', async ({ I }) => {
9
+ I.amOnPage('object-case-sensitive-property-search-true.html')
10
+ I.click('.json-editor-btn-edit_properties')
11
+ I.fillField('.property-selector-input', 'aaa')
12
+ I.see('aaa', '.form-check label')
13
+ I.dontSee('AAA', '.form-check label')
14
+ I.fillField('.property-selector-input', 'AAA')
15
+ I.see('AAA', '.form-check label')
16
+ I.dontSee('aaa', '.form-check label')
17
+
18
+ I.amOnPage('object-case-sensitive-property-search-false.html')
19
+ I.click('.json-editor-btn-edit_properties')
20
+ I.fillField('.property-selector-input', 'aaa')
21
+ I.see('aaa', '.form-check label')
22
+ I.see('AAA', '.form-check label')
23
+ I.fillField('.property-selector-input', 'AAA')
24
+ I.see('AAA', '.form-check label')
25
+ I.see('aaa', '.form-check label')
26
+ })
27
+
8
28
  Scenario('should respect property orders', async ({ I }) => {
9
29
  I.amOnPage('object.html')
10
30
  assert.strictEqual(await I.grabAttributeFrom('[data-schemapath^="root"] .row:nth-of-type(1) [data-schemapath^="root."]', 'data-schemapath'), 'root.age')
@@ -0,0 +1,8 @@
1
+ /* global Feature Scenario */
2
+
3
+ Feature('issues')
4
+
5
+ Scenario('GitHub issue 1330 should remain fixed @issue-1330 @multiselect', async ({ I }) => {
6
+ I.amOnPage('issues/issue-gh-1330.html')
7
+ I.waitForElement('[data-schemapath="root.test"] input[type="checkbox"]')
8
+ })
@@ -7,10 +7,12 @@ Scenario('GitHub issue 1338 should remain fixed @issue-1338', async ({ I }) => {
7
7
  I.waitForText('Value required')
8
8
  I.fillField('[id="root[field_a]"]', 'test')
9
9
  I.pressKey('Tab')
10
+ I.waitForElement('.invalid-feedback')
10
11
  I.dontSee('Value required')
11
12
  I.refreshPage()
12
13
  I.waitForText('Value required')
13
14
  I.fillField('[id="root[field_b]"]', 'test')
14
15
  I.pressKey('Tab')
16
+ I.waitForElement('.invalid-feedback')
15
17
  I.dontSee('Value required')
16
18
  })
@@ -0,0 +1,13 @@
1
+ /* global Feature Scenario */
2
+
3
+ Feature('GitHub issue 1364')
4
+
5
+ Scenario('GitHub issue 1364 should remain fixed @issue-1364', ({ I }) => {
6
+ I.amOnPage('issues/issue-gh-1364.html')
7
+ I.waitForElement('.je-ready')
8
+ I.waitForValue('#value', '{"engine":"none","child1":{}}')
9
+ I.selectOption('[id="root[engine]"]', 'test1')
10
+ I.waitForValue('#value', '{"engine":"test1","child1":{"L2Name":""},"L1Name":""}')
11
+ I.selectOption('[id="root[engine]"]', 'none')
12
+ I.waitForValue('#value', '{"engine":"none","child1":{}}')
13
+ })
@@ -0,0 +1,11 @@
1
+ /* global Feature Scenario */
2
+ const assert = require('assert')
3
+
4
+ Feature('GitHub issue 1367')
5
+
6
+ Scenario('GitHub issue 1367 should remain fixed @issue-1367', async ({ I }) => {
7
+ I.amOnPage('issues/issue-gh-1367.html')
8
+ I.waitForElement('.je-ready')
9
+ I.click('canvas')
10
+ assert.match(await I.grabValueFrom('#value'), /base64/)
11
+ })
@@ -0,0 +1,9 @@
1
+ /* global Feature Scenario */
2
+
3
+ Feature('issues')
4
+
5
+ Scenario('GitHub issue 1383 should remain fixed @issue-1383 @optional', async ({ I }) => {
6
+ I.amOnPage('issues/issue-gh-1383.html')
7
+ I.waitForElement('.je-ready')
8
+ I.waitForText('activity-timeout')
9
+ })
@@ -0,0 +1,9 @@
1
+ /* global Feature Scenario */
2
+
3
+ Feature('issues')
4
+
5
+ Scenario('GitHub issue 1384 should remain fixed @issue-1384 @optional', async ({ I }) => {
6
+ I.amOnPage('issues/issue-gh-1384.html')
7
+ I.waitForElement('.je-ready')
8
+ I.waitForText('Zope layout definition')
9
+ })
@@ -0,0 +1,13 @@
1
+ /* global Feature Scenario */
2
+
3
+ Feature('issues')
4
+
5
+ Scenario('GitHub issue 1410 should remain fixed @issue-1410', async ({ I }) => {
6
+ I.amOnPage('issues/issue-gh-1410.html')
7
+ I.waitForElement('.je-ready')
8
+ I.click('[data-schemapath="root.standard"] .json-editor-btn-edit_properties')
9
+ I.waitForInvisible('[data-schemapath="root.standard"] .json-editor-btn-add')
10
+ I.click('[data-schemapath="root.standard"] .json-editor-btn-edit_properties')
11
+ I.click('[data-schemapath="root.extras"] .json-editor-btn-edit_properties')
12
+ I.waitForVisible('[data-schemapath="root.extras"] .json-editor-btn-add')
13
+ })
@@ -0,0 +1,9 @@
1
+ /* global Feature Scenario */
2
+
3
+ Feature('issues')
4
+
5
+ Scenario('GitHub issue 1422 should remain fixed @issue-1422', async ({ I }) => {
6
+ I.amOnPage('issues/issue-gh-1422.html')
7
+ I.waitForElement('.je-ready')
8
+ I.waitForValue('#value', '{"req":5,"opt":5,"req_with_default":5}')
9
+ })
@@ -0,0 +1,4 @@
1
+ version: '3'
2
+ services:
3
+ chrome:
4
+ image: seleniarm/standalone-chromium:114.0
@@ -0,0 +1,62 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8"/>
5
+ <title>Selectize add item</title>
6
+ <link rel="stylesheet" id="theme-link" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
7
+ <link rel="stylesheet" id="iconlib-link" href="https://use.fontawesome.com/releases/v5.6.1/css/all.css">
8
+ <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/selectize.js/0.12.4/css/selectize.bootstrap3.css">
9
+ <script src="../../dist/jsoneditor.js"></script>
10
+ <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
11
+ <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/selectize.js/0.12.4/js/standalone/selectize.js"></script>
12
+ </head>
13
+ <body>
14
+
15
+ <div class="container">
16
+ <div class="row">
17
+ <div class="col-xs-12 col-md-6">
18
+ <div id='editor-container'></div>
19
+ </div>
20
+ <div class="col-xs-12 col-md-6">
21
+ <label for="value">value</label>
22
+ <textarea class="form-control" id="value" cols="30" rows="10"></textarea>
23
+ <button id="set-value">Set value</button>
24
+ </div>
25
+ </div>
26
+ </div>
27
+
28
+ <script>
29
+ var schema = {
30
+ "type": "array",
31
+ "format":"selectize",
32
+ "uniqueItems": true,
33
+ "items": {
34
+ "type": "string"
35
+ },
36
+ "options": {
37
+ "selectize": {
38
+ "create": true,
39
+ "plugins": ["remove_button"],
40
+ }
41
+ }
42
+ }
43
+ var editorContainer = document.querySelector('#editor-container')
44
+ var value = document.querySelector('#value')
45
+ var setValue = document.querySelector('#set-value')
46
+ var editor = new JSONEditor(editorContainer, {
47
+ schema: schema,
48
+ theme: 'bootstrap4',
49
+ iconlib: 'fontawesome'
50
+ })
51
+
52
+ editor.on('change', function () {
53
+ value.value = JSON.stringify(editor.getValue())
54
+ })
55
+
56
+ setValue.addEventListener('click', function () {
57
+ editor.setValue(JSON.parse(value.value))
58
+ })
59
+ </script>
60
+
61
+ </body>
62
+ </html>
@@ -0,0 +1,65 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8"/>
5
+ <title>dependentSchemas</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>
15
+
16
+ <style>
17
+ th {
18
+ white-space: nowrap;
19
+ }
20
+ </style>
21
+
22
+ <script>
23
+ var editorContainer = document.querySelector('#editor-container')
24
+ var schema = {
25
+ "title": "Array table responsive",
26
+ "format": "table",
27
+ "type": "array",
28
+ "minItems": 1,
29
+ "items": {
30
+ "title": "item",
31
+ "type": "object",
32
+ "properties": {
33
+ "property_a": {
34
+ "title": "A very long title",
35
+ "type": "string"
36
+ },
37
+ "property_b": {
38
+ "title": "Another long title",
39
+ "type": "string"
40
+ },
41
+ "property_c": {
42
+ "title": "Another long title too",
43
+ "type": "string"
44
+ },
45
+ "property_d": {
46
+ "title": "Another long title too",
47
+ "type": "string"
48
+ },
49
+ "property_e": {
50
+ "title": "Another long title too",
51
+ "type": "string"
52
+ }
53
+ }
54
+ }
55
+ }
56
+
57
+ var editor = new JSONEditor(editorContainer, {
58
+ schema: schema,
59
+ theme: 'bootstrap4',
60
+ iconlib: 'fontawesome',
61
+ })
62
+ </script>
63
+
64
+ </body>
65
+ </html>
@@ -0,0 +1,34 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8"/>
5
+ <title>button_state_mode</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>
15
+
16
+ <script>
17
+ var editorContainer = document.querySelector('#editor-container')
18
+ var schema = {
19
+ 'title': 'button_state_mode',
20
+ 'type': 'array',
21
+ 'items': {
22
+ 'type': 'number'
23
+ },
24
+ 'minItems': 3
25
+ }
26
+
27
+ var editor = new JSONEditor(editorContainer, {
28
+ schema: schema,
29
+ theme: 'bootstrap4'
30
+ })
31
+ </script>
32
+
33
+ </body>
34
+ </html>