@json-editor/json-editor 2.11.0 → 2.13.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 (89) hide show
  1. package/.env +1 -1
  2. package/CHANGELOG.md +19 -0
  3. package/README.md +90 -6
  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 +417 -227
  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 +66 -14
  13. package/docs/meta_schema.json +16 -1
  14. package/docs/radio.html +1 -1
  15. package/docs/scripts/ajv-validator.js +8695 -0
  16. package/docs/select2.html +1 -1
  17. package/docs/selectize.html +2 -5
  18. package/docs/signature.html +12 -11
  19. package/docs/wysiwyg.html +1 -1
  20. package/package.json +1 -1
  21. package/src/core.js +10 -1
  22. package/src/defaults.js +3 -1
  23. package/src/editor.js +19 -1
  24. package/src/editors/array/selectize.js +0 -2
  25. package/src/editors/array.js +24 -13
  26. package/src/editors/base64.js +9 -0
  27. package/src/editors/button.js +8 -2
  28. package/src/editors/integer.js +3 -2
  29. package/src/editors/multiple.js +3 -0
  30. package/src/editors/number.js +4 -2
  31. package/src/editors/object.js +71 -3
  32. package/src/editors/signature.js +16 -16
  33. package/src/editors/simplemde.js +2 -1
  34. package/src/editors/string.js +4 -0
  35. package/src/editors/table.js +17 -14
  36. package/src/resolvers.js +13 -6
  37. package/src/schemaloader.js +13 -0
  38. package/src/theme.js +4 -0
  39. package/src/themes/bootstrap3.js +6 -0
  40. package/src/themes/bootstrap4.js +6 -0
  41. package/src/themes/bootstrap5.js +6 -0
  42. package/src/validator.js +28 -0
  43. package/tests/codeceptjs/codecept.json +1 -1
  44. package/tests/codeceptjs/constrains/contains_test.js +3 -2
  45. package/tests/codeceptjs/constrains/dependentRequired_test.js +33 -0
  46. package/tests/codeceptjs/constrains/dependentSchemas_test.js +1 -0
  47. package/tests/codeceptjs/core_test.js +14 -4
  48. package/tests/codeceptjs/editors/advanced_test.js +1 -1
  49. package/tests/codeceptjs/editors/array_test.js +59 -0
  50. package/tests/codeceptjs/editors/autocomplete_test.js +3 -1
  51. package/tests/codeceptjs/editors/object_test.js +20 -0
  52. package/tests/codeceptjs/editors/tabs_test.js +1 -1
  53. package/tests/codeceptjs/issues/issue-gh-1330_test.js +8 -0
  54. package/tests/codeceptjs/issues/issue-gh-1338_test.js +2 -0
  55. package/tests/codeceptjs/issues/issue-gh-1364_test.js +13 -0
  56. package/tests/codeceptjs/issues/issue-gh-1367_test.js +11 -0
  57. package/tests/codeceptjs/issues/issue-gh-1383_test.js +9 -0
  58. package/tests/codeceptjs/issues/issue-gh-1384_test.js +9 -0
  59. package/tests/codeceptjs/issues/issue-gh-1410_test.js +13 -0
  60. package/tests/codeceptjs/issues/issue-gh-1422_test.js +9 -0
  61. package/tests/codeceptjs/issues/issue-gh-1431_test.js +12 -0
  62. package/tests/codeceptjs/issues/issue-gh-1439_test.js +12 -0
  63. package/tests/docker-compose-local.yml +4 -0
  64. package/tests/pages/array-header-template.html +59 -0
  65. package/tests/pages/array-selectize-create.html +62 -0
  66. package/tests/pages/array-table-responsive.html +65 -0
  67. package/tests/pages/button-icons.html +1 -1
  68. package/tests/pages/button_state_mode_1.html +34 -0
  69. package/tests/pages/button_state_mode_2.html +35 -0
  70. package/tests/pages/dependentRequired.html +71 -0
  71. package/tests/pages/issues/issue-gh-1330.html +52 -0
  72. package/tests/pages/issues/issue-gh-1364.html +64 -0
  73. package/tests/pages/issues/issue-gh-1367.html +49 -0
  74. package/tests/pages/issues/issue-gh-1383.html +31 -0
  75. package/tests/pages/issues/issue-gh-1383.json +14 -0
  76. package/tests/pages/issues/issue-gh-1384.html +31 -0
  77. package/tests/pages/issues/issue-gh-1384.json +36 -0
  78. package/tests/pages/issues/issue-gh-1410.html +57 -0
  79. package/tests/pages/issues/issue-gh-1422.html +68 -0
  80. package/tests/pages/issues/issue-gh-1431.html +49 -0
  81. package/tests/pages/issues/issue-gh-1439.html +69 -0
  82. package/tests/pages/keep_only_existing_values.html +1 -1
  83. package/tests/pages/load-events.html +60 -0
  84. package/tests/pages/meta-schema.html +16 -2
  85. package/tests/pages/meta_schema.json +5 -1
  86. package/tests/pages/object-case-sensitive-property-search-false.html +41 -0
  87. package/tests/pages/object-case-sensitive-property-search-true.html +41 -0
  88. package/dist/dev/jsoneditor.js +0 -3687
  89. package/dist/jsoneditor.js.map +0 -1
package/src/resolvers.js CHANGED
@@ -1,11 +1,14 @@
1
- /* Use "multiple" as a fall back for everything */
1
+ /* Use "multiple" as a fallback for everything */
2
2
  const defaultResolver = schema => typeof schema.type !== 'string' && 'multiple'
3
3
 
4
+ /* If the type is a script type, then presume the Editor's type is "string" until later resolvers decide otherwise */
5
+ const defaultResolverString = schema => typeof schema.type === 'string' && 'string'
6
+
4
7
  /* If the type is not set but properties are defined, we can infer the type is actually object */
5
8
  const object = schema => !schema.type && schema.properties && 'object'
6
9
 
7
- /* If the type is set and it's a basic type, use the primitive editor */
8
- const primitive = schema => typeof schema.type === 'string' && schema.type
10
+ /* If type is set, and it's a basic JSON type, use the primitive editor */
11
+ const primitive = schema => typeof schema.type === 'string' && ['string', 'number', 'integer', 'boolean', 'null', 'array', 'object'].includes(schema.type) && schema.type
9
12
 
10
13
  /* Use specialized editor for signatures */
11
14
  const signature = schema => schema.type === 'string' && schema.format === 'signature' && 'signature'
@@ -61,7 +64,11 @@ const enumeratedProperties = schema => {
61
64
  }
62
65
 
63
66
  /* Specialized editors for arrays of strings */
64
- const arraysOfStrings = schema => {
67
+ const arraysOfStrings = (schema, je) => {
68
+ if (schema.items) {
69
+ schema.items = je.expandSchema(schema.items)
70
+ }
71
+
65
72
  if (schema.type === 'array' && schema.items && !(Array.isArray(schema.items)) && ['string', 'number', 'integer'].includes(schema.items.type)) {
66
73
  if (schema.format === 'choices') return 'arrayChoices'
67
74
  if (schema.uniqueItems) {
@@ -117,7 +124,7 @@ const markdown = schema => schema.type === 'string' && schema.format === 'markdo
117
124
  const xhtml = schema => schema.type === 'string' && ['xhtml', 'bbcode'].includes(schema.format) && 'sceditor'
118
125
 
119
126
  /* 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']
127
+ 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
128
  const ace = schema => schema.type === 'string' && aceModes.includes(schema.format) && 'ace'
122
129
 
123
130
  const ip = schema => schema.type === 'string' && ['ip', 'ipv4', 'ipv6', 'hostname'].includes(schema.format) && 'ip'
@@ -125,4 +132,4 @@ const ip = schema => schema.type === 'string' && ['ip', 'ipv4', 'ipv6', 'hostnam
125
132
  const colorPicker = schema => schema.type === 'string' && schema.format === 'color' && 'colorpicker'
126
133
 
127
134
  /* Export resolvers in order of discovery, first to last */
128
- export const resolvers = [colorPicker, ip, ace, xhtml, markdown, jodit, autoComplete, uuid, info, button, stepper, describeBy, starratings, date, oneOf, ifThenElse, arraysOfStrings, enumeratedProperties, enumSource, table, upload, base64, any, boolean, signature, primitive, object, defaultResolver]
135
+ export const resolvers = [colorPicker, ip, ace, xhtml, markdown, jodit, autoComplete, uuid, info, button, stepper, describeBy, starratings, date, oneOf, ifThenElse, arraysOfStrings, enumeratedProperties, enumSource, table, upload, base64, any, boolean, signature, primitive, object, defaultResolver, defaultResolverString]
@@ -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
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "tests": "./**/*_test.js",
3
- "timeout": 10000,
3
+ "timeout": 30,
4
4
  "output": "./output",
5
5
  "plugins": {
6
6
  "pauseOnFail": {}
@@ -7,18 +7,18 @@ Scenario('should display contains validation errors @contains', ({ I }) => {
7
7
  I.waitForElement('.je-ready')
8
8
  I.waitForText('No items match contains')
9
9
  I.click('.json-editor-btn-add')
10
+ I.waitForInvisible('.alert-danger')
10
11
  I.dontSee('No items match contains')
11
12
  })
12
13
 
13
14
  Scenario('should display @minContains validation errors @contains', ({ I }) => {
14
15
  I.amOnPage('minContains.html')
15
16
  I.waitForElement('.je-ready')
16
- I.dontSee('No items match contains')
17
17
  I.waitForText('Contains match count 0 is less than minimum contains count of 2')
18
18
  I.click('.json-editor-btn-add')
19
- I.dontSee('No items match contains')
20
19
  I.waitForText('Contains match count 1 is less than minimum contains count of 2')
21
20
  I.click('.json-editor-btn-add')
21
+ I.waitForInvisible('.alert-danger')
22
22
  I.dontSee('No items match contains')
23
23
  I.dontSee('minimum contains count of 2')
24
24
  })
@@ -28,6 +28,7 @@ Scenario('should display @maxContains validation errors @contains', ({ I }) => {
28
28
  I.waitForElement('.je-ready')
29
29
  I.waitForText('No items match contains')
30
30
  I.click('.json-editor-btn-add')
31
+ I.waitForInvisible('.alert-danger')
31
32
  I.dontSee('No items match contains')
32
33
  I.click('.json-editor-btn-add')
33
34
  I.dontSee('No items match contains')
@@ -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
+ })
@@ -9,6 +9,7 @@ Scenario('@dependentSchemas should display validation errors', ({ I }) => {
9
9
  I.click('[data-schemapath="root.credit_card"] .json-editor-opt-in')
10
10
  I.waitForText('Object is missing the required property \'billing_address\'')
11
11
  I.click('[data-schemapath="root.billing_address"] .json-editor-opt-in')
12
+ I.waitForInvisible('.alert-danger')
12
13
  I.dontSee('Object is missing the required property \'billing_address\'')
13
14
  I.click('[data-schemapath="root.credit_card"] .json-editor-opt-in')
14
15
  I.dontSee('Object is missing the required property \'billing_address\'')
@@ -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')
@@ -79,18 +89,18 @@ Scenario('should set and get individual values', async ({ I }) => {
79
89
  I.waitForValue('.value', '"john kaminski"')
80
90
  })
81
91
 
82
- Scenario('should watch a specific field for changes', async ({ I }) => {
92
+ Scenario('should watch a specific field for changes @core @change', async ({ I }) => {
83
93
  I.amOnPage('core.html')
84
94
  I.dontSeeElement('.name-changed')
85
95
  I.click('.set-individual-value')
86
- I.seeElement('.name-changed')
96
+ I.waitForElement('.name-changed')
87
97
  })
88
98
 
89
- Scenario('should watch form for changes', async ({ I }) => {
99
+ Scenario('should watch form for changes @core @change', async ({ I }) => {
90
100
  I.amOnPage('core.html')
91
101
  I.dontSeeElement('.form-changed')
92
102
  I.click('.set-value')
93
- I.seeElement('.form-changed')
103
+ I.waitForElement('.form-changed')
94
104
  })
95
105
 
96
106
  Scenario('should change the form if form_name_root option is set @core', async ({ I }) => {
@@ -1,6 +1,6 @@
1
1
  /* global Feature Scenario */
2
2
 
3
- Feature('Advanced Editor')
3
+ Feature('Advanced Editor @advance-editor')
4
4
 
5
5
  Scenario('test validation & delete', ({ I }) => {
6
6
  I.amOnPage('advanced.html')
@@ -4,6 +4,43 @@ const { DEFAULT_WAIT_TIME } = require('../test-config')
4
4
 
5
5
  Feature('array')
6
6
 
7
+ Scenario('Should display properties enum titles in items headerTemplate @headerTemplate', async ({ I }) => {
8
+ I.amOnPage('array-header-template.html')
9
+ I.waitForElement('.je-ready', DEFAULT_WAIT_TIME)
10
+ I.waitForText('Dog', DEFAULT_WAIT_TIME, '.nav-link span')
11
+ I.waitForText('Cat', DEFAULT_WAIT_TIME, '.nav-link span')
12
+ })
13
+
14
+ Scenario('Should set buttons states correctly @button_state_mode', async ({ I }) => {
15
+ I.amOnPage('button_state_mode_1.html')
16
+ I.waitForElement('.je-ready', DEFAULT_WAIT_TIME)
17
+ I.waitForElement('.json-editor-btntype-add', DEFAULT_WAIT_TIME)
18
+ I.waitForElement('.json-editor-btn-movedown', DEFAULT_WAIT_TIME)
19
+ I.waitForElement('.json-editor-btn-moveup', DEFAULT_WAIT_TIME)
20
+ I.dontSeeElement('.json-editor-btntype-delete')
21
+ I.dontSeeElement('.json-editor-btntype-deletelast')
22
+ I.dontSeeElement('.json-editor-btntype-deleteall')
23
+ I.click('.json-editor-btntype-add')
24
+ I.waitForElement('.json-editor-btntype-delete')
25
+ I.waitForElement('.json-editor-btntype-deletelast')
26
+ I.waitForElement('.json-editor-btntype-deleteall')
27
+
28
+ I.amOnPage('button_state_mode_2.html')
29
+ I.waitForElement('.je-ready', DEFAULT_WAIT_TIME)
30
+ I.waitForElement('.json-editor-btntype-add', DEFAULT_WAIT_TIME)
31
+ I.waitForElement('.json-editor-btn-movedown', DEFAULT_WAIT_TIME)
32
+ I.waitForElement('.json-editor-btn-moveup', DEFAULT_WAIT_TIME)
33
+ I.waitForElement('.json-editor-btntype-delete', DEFAULT_WAIT_TIME)
34
+ I.waitForElement('.json-editor-btntype-deletelast', DEFAULT_WAIT_TIME)
35
+ I.seeDisabledAttribute('.json-editor-btntype-delete')
36
+ I.seeDisabledAttribute('.json-editor-btntype-deletelast')
37
+ I.seeDisabledAttribute('.json-editor-btntype-deleteall')
38
+ I.click('.json-editor-btntype-add')
39
+ I.dontSeeDisabledAttribute('.json-editor-btntype-delete')
40
+ I.dontSeeDisabledAttribute('.json-editor-btntype-deletelast')
41
+ I.dontSeeDisabledAttribute('.json-editor-btntype-deleteall')
42
+ })
43
+
7
44
  Scenario('should have correct initial value', async ({ I }) => {
8
45
  I.amOnPage('array.html')
9
46
  I.click('.get-value')
@@ -963,3 +1000,25 @@ Scenario('should work well with selectize multiselect editors', async ({ I }) =>
963
1000
  I.seeElement('[data-schemapath="root.0"] .selectize-dropdown-content [data-value="3"]')
964
1001
  I.seeElement('[data-schemapath="root.0"] .selectize-dropdown-content [data-value="4"]')
965
1002
  })
1003
+
1004
+ Scenario('should be possible to add items to selectize array @selectize-add', async ({ I }) => {
1005
+ I.amOnPage('array-selectize-create.html')
1006
+ I.click('.selectize-input')
1007
+ I.pressKey('g')
1008
+ I.pressKey('Enter')
1009
+ I.pressKey('r')
1010
+ I.pressKey('Enter')
1011
+ I.pressKey('e')
1012
+ I.pressKey('Enter')
1013
+ I.pressKey('a')
1014
+ I.pressKey('Enter')
1015
+ I.pressKey('t')
1016
+ I.pressKey('Enter')
1017
+ I.waitForValue('#value', '["g","r","e","a","t"]')
1018
+ })
1019
+
1020
+ Scenario('Tables should have a container parent that makes tables responsive @array-table', async ({ I }) => {
1021
+ I.amOnPage('array-table-responsive.html')
1022
+ I.waitForElement('.je-ready', DEFAULT_WAIT_TIME)
1023
+ I.waitForElement('.table-responsive')
1024
+ })
@@ -5,7 +5,9 @@ Feature('autocomplete')
5
5
  Scenario('autocomplete should work @autocomplete', async ({ I }) => {
6
6
  I.amOnPage('autocomplete.html')
7
7
  I.waitForElement('.je-ready', 10)
8
- I.fillField('root', 'ir')
8
+ I.click('[name="root"]')
9
+ I.pressKey('i')
10
+ I.pressKey('r')
9
11
  I.waitForText('iran', 20, '.autocomplete-result-list')
10
12
  I.waitForText('iraq', 20, '.autocomplete-result-list')
11
13
  I.click('iraq', '.autocomplete-result:nth-child(2)')
@@ -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')
@@ -4,7 +4,7 @@ const { DEFAULT_WAIT_TIME } = require('../test-config')
4
4
 
5
5
  Feature('Tabs')
6
6
 
7
- Scenario('test top-tabs', ({ I }) => {
7
+ Scenario('test @top-tabs', ({ I }) => {
8
8
  I.amOnPage('tabs.html')
9
9
  I.waitForElement('[data-schemapath="root"] .json-editor-btn-add')
10
10
  I.click('[data-schemapath="root"] .json-editor-btn-add')
@@ -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.waitForInvisible('.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.waitForInvisible('.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,12 @@
1
+ /* global Feature Scenario */
2
+
3
+ Feature('issues')
4
+
5
+ Scenario('GitHub issue 1431 should remain fixed @issue-1431', async ({ I }) => {
6
+ I.amOnPage('issues/issue-gh-1431.html')
7
+ I.waitForElement('.je-ready')
8
+ I.waitForElement('.CodeMirror')
9
+ I.click('.CodeMirror')
10
+ I.pressKeys('simple-mde')
11
+ I.waitForValue('#value', '{"name":"simple-mde"}')
12
+ })
@@ -0,0 +1,12 @@
1
+ /* global Feature Scenario */
2
+
3
+ Feature('issues')
4
+
5
+ Scenario('GitHub issue 1439 should remain fixed @issue-1439', async ({ I }) => {
6
+ I.amOnPage('issues/issue-gh-1439.html')
7
+ I.waitForElement('.je-ready')
8
+ I.waitForElement('[name="root[wrong]"]')
9
+ I.waitForElement('[data-schemapath="root.correct"] button')
10
+ I.waitForText('Button text')
11
+ I.waitForValue('#value', '{"wrong":""}')
12
+ })
@@ -0,0 +1,4 @@
1
+ version: '3'
2
+ services:
3
+ chrome:
4
+ image: seleniarm/standalone-chromium:114.0
@@ -0,0 +1,59 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8"/>
5
+ <title>array-header-template</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
+ const editorContainer = document.querySelector('#editor-container')
18
+ const schema1 = {
19
+ "title": "Pets",
20
+ "format": "tabs",
21
+ "type": "array",
22
+ "minItems": 1,
23
+ "default": [
24
+ {
25
+ "pet": "pet_1"
26
+ },
27
+ {
28
+ "pet": "pet_2"
29
+ }
30
+ ],
31
+ "items": {
32
+ "title": "Pets",
33
+ "type": "object",
34
+ "headerTemplate": "{{ properties.pet.enumTitle }}",
35
+ "properties": {
36
+ "pet": {
37
+ "title": "Pet",
38
+ "type": "string",
39
+ "enum": [ "pet_1", "pet_2" ],
40
+ "options": {
41
+ "enum_titles": [ "Dog", "Cat" ]
42
+ }
43
+ }
44
+ }
45
+ }
46
+ }
47
+
48
+ const editor = new JSONEditor(editorContainer, {
49
+ schema: schema1,
50
+ theme: 'bootstrap4',
51
+ iconlib: 'fontawesome',
52
+ disable_collapse: true,
53
+ disable_edit_json: true,
54
+ disable_properties: true
55
+ })
56
+ </script>
57
+
58
+ </body>
59
+ </html>