@json-editor/json-editor 1.4.0-beta.0 → 1.17.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 (435) hide show
  1. package/.claude/settings.local.json +8 -0
  2. package/.env +2 -0
  3. package/.env-dist +2 -0
  4. package/.eslintrc +10 -0
  5. package/.github/PULL_REQUEST_TEMPLATE.md +9 -0
  6. package/.github/workflows/build.yml +70 -0
  7. package/.travis.yml +62 -16
  8. package/CHANGELOG.md +483 -113
  9. package/CONTRIBUTING.md +43 -4
  10. package/Makefile +26 -0
  11. package/README.md +632 -121
  12. package/README_ADDON.md +577 -0
  13. package/UPGRADING.md +46 -0
  14. package/build/CssToJson.js +55 -0
  15. package/codecept.conf.js +35 -0
  16. package/config/.eslintrc +7 -0
  17. package/config/codeceptjs_helpers.js +146 -0
  18. package/config/helpers.js +10 -0
  19. package/config/karma.conf.js +89 -0
  20. package/config/readme.md +31 -0
  21. package/config/webpack.common.js +71 -0
  22. package/config/webpack.dev.js +15 -0
  23. package/config/webpack.nonmin.js +19 -0
  24. package/config/webpack.prod.js +24 -0
  25. package/dist/jsoneditor.js +2 -11550
  26. package/dist/jsoneditor.js.LICENSE.txt +15 -0
  27. package/dist/nonmin/jsoneditor.js +31392 -0
  28. package/dist/nonmin/jsoneditor.js.map +1 -0
  29. package/docs/basic.html +2 -2
  30. package/docs/basic_person.json +2 -1
  31. package/docs/choices.html +86 -0
  32. package/docs/cleave.html +11 -19
  33. package/docs/colorpicker.html +194 -0
  34. package/docs/css_integration.html +56 -54
  35. package/docs/custom-editor.html +92 -0
  36. package/docs/datetime.html +48 -21
  37. package/docs/describedby.html +42 -35
  38. package/docs/enumsource.html +67 -0
  39. package/docs/form-submission.html +162 -0
  40. package/docs/imask.html +192 -0
  41. package/docs/index.html +600 -582
  42. package/docs/materialize_css.html +1 -1
  43. package/docs/meta-schema.html +793 -0
  44. package/docs/meta_schema.json +446 -400
  45. package/docs/polyfills/assign.js +29 -0
  46. package/docs/radio.html +9 -17
  47. package/docs/recursive.html +15 -17
  48. package/docs/scripts/ajv-validator.js +8695 -0
  49. package/docs/select2.html +15 -9
  50. package/docs/selectize.html +11 -9
  51. package/docs/signature.html +12 -11
  52. package/docs/starrating.html +5 -17
  53. package/docs/upload.html +33 -23
  54. package/docs/uuid.html +70 -0
  55. package/docs/wysiwyg.html +14 -7
  56. package/jasmine.json +11 -0
  57. package/package.json +74 -25
  58. package/release-notes.md +90 -0
  59. package/src/core.js +411 -611
  60. package/src/defaults.js +381 -327
  61. package/src/editor.js +733 -544
  62. package/src/editors/ace.js +90 -0
  63. package/src/editors/array/choices.js +104 -0
  64. package/src/editors/array/select2.js +112 -0
  65. package/src/editors/array/selectize.js +107 -130
  66. package/src/editors/array.css +9 -0
  67. package/src/editors/array.css.js +3 -0
  68. package/src/editors/array.js +812 -695
  69. package/src/editors/autocomplete.js +59 -0
  70. package/src/editors/base64.js +148 -129
  71. package/src/editors/button.js +104 -0
  72. package/src/editors/checkbox.js +111 -76
  73. package/src/editors/choices.css +3 -0
  74. package/src/editors/choices.css.js +3 -0
  75. package/src/editors/choices.js +71 -0
  76. package/src/editors/colorpicker.js +105 -0
  77. package/src/editors/datetime.js +93 -79
  78. package/src/editors/describedby.js +141 -125
  79. package/src/editors/enum.js +131 -116
  80. package/src/editors/hidden.js +100 -86
  81. package/src/editors/index.js +81 -0
  82. package/src/editors/info.js +28 -0
  83. package/src/editors/integer.js +21 -8
  84. package/src/editors/ip.js +36 -0
  85. package/src/editors/jodit.js +66 -0
  86. package/src/editors/multiple.js +380 -241
  87. package/src/editors/multiselect.js +207 -207
  88. package/src/editors/null.js +15 -11
  89. package/src/editors/number.js +39 -30
  90. package/src/editors/object.css +41 -0
  91. package/src/editors/object.css.js +3 -0
  92. package/src/editors/object.js +1190 -1068
  93. package/src/editors/radio.js +117 -101
  94. package/src/editors/sceditor.js +74 -0
  95. package/src/editors/select.js +318 -342
  96. package/src/editors/select2.js +112 -0
  97. package/src/editors/selectize.js +89 -338
  98. package/src/editors/signature.js +100 -104
  99. package/src/editors/simplemde.js +103 -0
  100. package/src/{styles → editors}/starrating.css +11 -2
  101. package/src/editors/starrating.css.js +3 -0
  102. package/src/editors/starrating.js +126 -95
  103. package/src/editors/stepper.js +27 -0
  104. package/src/editors/string.js +352 -426
  105. package/src/editors/table.js +486 -410
  106. package/src/editors/upload.js +297 -131
  107. package/src/editors/uuid.js +49 -0
  108. package/src/iconlib.js +22 -27
  109. package/src/iconlibs/bootstrap.js +28 -0
  110. package/src/iconlibs/bootstrap2.js +28 -17
  111. package/src/iconlibs/bootstrap3.js +28 -17
  112. package/src/iconlibs/fontawesome3.js +28 -17
  113. package/src/iconlibs/fontawesome4.js +28 -18
  114. package/src/iconlibs/fontawesome5.js +28 -18
  115. package/src/iconlibs/foundation2.js +24 -17
  116. package/src/iconlibs/foundation3.js +28 -17
  117. package/src/iconlibs/index.js +27 -0
  118. package/src/iconlibs/jqueryui.js +28 -17
  119. package/src/iconlibs/materialicons.js +49 -44
  120. package/src/iconlibs/openiconic.js +28 -0
  121. package/src/iconlibs/spectre.js +28 -0
  122. package/src/resolvers.js +135 -0
  123. package/src/schemaloader.js +639 -0
  124. package/src/style.css +157 -0
  125. package/src/style.css.js +3 -0
  126. package/src/templates/default.js +46 -51
  127. package/src/templates/ejs.js +8 -10
  128. package/src/templates/handlebars.js +1 -3
  129. package/src/templates/hogan.js +7 -9
  130. package/src/templates/index.js +21 -0
  131. package/src/templates/lodash.js +6 -8
  132. package/src/templates/markup.js +6 -8
  133. package/src/templates/mustache.js +6 -8
  134. package/src/templates/swig.js +1 -3
  135. package/src/templates/underscore.js +6 -8
  136. package/src/theme.js +717 -433
  137. package/src/themes/barebones.css +35 -0
  138. package/src/themes/barebones.css.js +3 -0
  139. package/src/themes/barebones.js +31 -0
  140. package/src/themes/bootstrap2.js +302 -265
  141. package/src/themes/bootstrap3.css +53 -0
  142. package/src/themes/bootstrap3.css.js +3 -0
  143. package/src/themes/bootstrap3.js +355 -262
  144. package/src/themes/bootstrap4.css +89 -0
  145. package/src/themes/bootstrap4.css.js +3 -0
  146. package/src/themes/bootstrap4.js +743 -237
  147. package/src/themes/bootstrap5.css +97 -0
  148. package/src/themes/bootstrap5.css.js +3 -0
  149. package/src/themes/bootstrap5.js +687 -0
  150. package/src/themes/foundation.js +535 -472
  151. package/src/themes/html.css +60 -0
  152. package/src/themes/html.css.js +3 -0
  153. package/src/themes/html.js +69 -82
  154. package/src/themes/index.js +29 -0
  155. package/src/themes/jqueryui.js +181 -167
  156. package/src/themes/materialize.js +263 -292
  157. package/src/themes/spectre.css +208 -0
  158. package/src/themes/spectre.css.js +3 -0
  159. package/src/themes/spectre.js +443 -0
  160. package/src/themes/tailwind.css +303 -0
  161. package/src/themes/tailwind.css.js +3 -0
  162. package/src/themes/tailwind.js +469 -0
  163. package/src/utilities.js +127 -68
  164. package/src/validator.js +909 -565
  165. package/src/validators/ip-validator.js +51 -0
  166. package/tests/Dockerfile +3 -0
  167. package/tests/README.md +25 -5
  168. package/tests/codeceptjs/codecept.json +9 -2
  169. package/tests/codeceptjs/constrains/contains_test.js +37 -0
  170. package/tests/codeceptjs/constrains/dependentRequired_test.js +33 -0
  171. package/tests/codeceptjs/constrains/dependentSchemas_test.js +16 -0
  172. package/tests/codeceptjs/constrains/if-then-else_test.js +186 -0
  173. package/tests/codeceptjs/core_test.js +534 -63
  174. package/tests/codeceptjs/editors/advanced_test.js +12 -9
  175. package/tests/codeceptjs/editors/array_any_of_test.js +50 -0
  176. package/tests/codeceptjs/editors/array_test.js +923 -657
  177. package/tests/codeceptjs/editors/autocomplete_test.js +15 -0
  178. package/tests/codeceptjs/editors/button_test.js +50 -0
  179. package/tests/codeceptjs/editors/checkbox_test.js +21 -6
  180. package/tests/codeceptjs/editors/colorpicker_test.js +29 -0
  181. package/tests/codeceptjs/editors/datetime_test.js +33 -0
  182. package/tests/codeceptjs/editors/inheritance_test.js +10 -0
  183. package/tests/codeceptjs/editors/integer_test.js +82 -64
  184. package/tests/codeceptjs/editors/jodit_test.js +23 -0
  185. package/tests/codeceptjs/editors/multiple_test.js +27 -0
  186. package/tests/codeceptjs/editors/multiselect_test.js +6 -7
  187. package/tests/codeceptjs/editors/number_test.js +75 -60
  188. package/tests/codeceptjs/editors/object_test.js +322 -80
  189. package/tests/codeceptjs/editors/option-no_default_values_test.js +42 -0
  190. package/tests/codeceptjs/editors/programmatic-changes_test.js +20 -0
  191. package/tests/codeceptjs/editors/purify_test.js +26 -0
  192. package/tests/codeceptjs/editors/radio_test.js +9 -0
  193. package/tests/codeceptjs/editors/range_test.js +10 -0
  194. package/tests/codeceptjs/editors/rating_test.js +10 -10
  195. package/tests/codeceptjs/editors/select_test.js +47 -18
  196. package/tests/codeceptjs/editors/starrating_test.js +15 -0
  197. package/tests/codeceptjs/editors/stepper_test.js +37 -0
  198. package/tests/codeceptjs/editors/string_test.js +107 -91
  199. package/tests/codeceptjs/editors/table-confirm-delete_test.js +60 -54
  200. package/tests/codeceptjs/editors/tabs_test.js +15 -11
  201. package/tests/codeceptjs/editors/uuid_test.js +48 -0
  202. package/tests/codeceptjs/editors/validation_test.js +13 -9
  203. package/tests/codeceptjs/issues/issue-gh-1133_test.js +9 -0
  204. package/tests/codeceptjs/issues/issue-gh-1158-2_test.js +10 -0
  205. package/tests/codeceptjs/issues/issue-gh-1158_test.js +8 -0
  206. package/tests/codeceptjs/issues/issue-gh-1164_test.js +9 -0
  207. package/tests/codeceptjs/issues/issue-gh-1171_test.js +11 -0
  208. package/tests/codeceptjs/issues/issue-gh-1211_test.js +17 -0
  209. package/tests/codeceptjs/issues/issue-gh-1257_test.js +11 -0
  210. package/tests/codeceptjs/issues/issue-gh-1272_test.js +21 -0
  211. package/tests/codeceptjs/issues/issue-gh-1330_test.js +8 -0
  212. package/tests/codeceptjs/issues/issue-gh-1338_test.js +18 -0
  213. package/tests/codeceptjs/issues/issue-gh-1347_test.js +8 -0
  214. package/tests/codeceptjs/issues/issue-gh-1364_test.js +13 -0
  215. package/tests/codeceptjs/issues/issue-gh-1367_test.js +11 -0
  216. package/tests/codeceptjs/issues/issue-gh-1383_test.js +9 -0
  217. package/tests/codeceptjs/issues/issue-gh-1384_test.js +9 -0
  218. package/tests/codeceptjs/issues/issue-gh-1410_test.js +13 -0
  219. package/tests/codeceptjs/issues/issue-gh-1422_test.js +9 -0
  220. package/tests/codeceptjs/issues/issue-gh-1431_test.js +12 -0
  221. package/tests/codeceptjs/issues/issue-gh-1439_test.js +12 -0
  222. package/tests/codeceptjs/issues/issue-gh-1452_test.js +10 -0
  223. package/tests/codeceptjs/issues/issue-gh-1453_test.js +18 -0
  224. package/tests/codeceptjs/issues/issue-gh-1461_test.js +14 -0
  225. package/tests/codeceptjs/issues/issue-gh-1463_test.js +9 -0
  226. package/tests/codeceptjs/issues/issue-gh-1471_test.js +17 -0
  227. package/tests/codeceptjs/issues/issue-gh-1485_test.js +13 -0
  228. package/tests/codeceptjs/issues/issue-gh-1491_test.js +9 -0
  229. package/tests/codeceptjs/issues/issue-gh-1525_test.js +9 -0
  230. package/tests/codeceptjs/issues/issue-gh-1536_test.js +12 -0
  231. package/tests/codeceptjs/issues/issue-gh-1538_test.js +10 -0
  232. package/tests/codeceptjs/issues/issue-gh-1541_test.js +8 -0
  233. package/tests/codeceptjs/issues/issue-gh-1559_test.js +15 -0
  234. package/tests/codeceptjs/issues/issue-gh-1562_test.js +12 -0
  235. package/tests/codeceptjs/issues/issue-gh-1586_test.js +15 -0
  236. package/tests/codeceptjs/issues/issue-gh-1636_test.js +9 -0
  237. package/tests/codeceptjs/issues/issue-gh-795_test.js +13 -0
  238. package/tests/codeceptjs/issues/issue-gh-810_test.js +52 -0
  239. package/tests/codeceptjs/issues/issue-gh-812_test.js +25 -0
  240. package/tests/codeceptjs/meta-schema_test.js +85 -0
  241. package/tests/codeceptjs/schemaloader_test.js +14 -0
  242. package/tests/codeceptjs/steps.d.ts +13 -0
  243. package/tests/codeceptjs/steps_file.js +4 -4
  244. package/tests/codeceptjs/test-config.js +3 -0
  245. package/tests/codeceptjs/themes_test.js +564 -0
  246. package/tests/docker-compose-local.yml +5 -0
  247. package/tests/docker-compose.yml +11 -19
  248. package/tests/fixtures/basic_person.json +2 -1
  249. package/tests/fixtures/definitions.json +22 -0
  250. package/tests/fixtures/nested_object.json +26 -0
  251. package/tests/fixtures/properties.json +20 -0
  252. package/tests/fixtures/some_types.json +32 -0
  253. package/tests/fixtures/validation.json +1347 -0
  254. package/tests/pages/_demo.html +475 -0
  255. package/tests/pages/advanced.html +1 -1
  256. package/tests/pages/anyof-2.html +91 -0
  257. package/tests/pages/anyof.html +82 -0
  258. package/tests/pages/array-anyof.html +145 -0
  259. package/tests/pages/array-checkboxes-infotext.html +55 -0
  260. package/tests/pages/array-checkboxes.html +5 -2
  261. package/tests/pages/array-choices.html +48 -0
  262. package/tests/pages/array-events-table.html +70 -0
  263. package/tests/pages/array-events.html +75 -0
  264. package/tests/pages/array-header-template.html +60 -0
  265. package/tests/pages/array-integers.html +5 -2
  266. package/tests/pages/array-multiselects.html +5 -2
  267. package/tests/pages/array-nested-arrays.html +5 -2
  268. package/tests/pages/array-numbers.html +5 -2
  269. package/tests/pages/array-objects.html +5 -2
  270. package/tests/pages/array-ratings.html +5 -2
  271. package/tests/pages/array-selectize-create.html +63 -0
  272. package/tests/pages/array-selectize.html +10 -8
  273. package/tests/pages/array-selects.html +5 -2
  274. package/tests/pages/array-strings.html +5 -2
  275. package/tests/pages/array-table-responsive.html +66 -0
  276. package/tests/pages/array-unique-items-sort.html +81 -0
  277. package/tests/pages/array.html +5 -2
  278. package/tests/pages/assets/autocomplete.css +1 -0
  279. package/tests/pages/assets/autocomplete.min.js +1 -0
  280. package/tests/pages/assets/pages.css +130 -0
  281. package/tests/pages/autocomplete.html +72 -0
  282. package/tests/pages/button-callbacks.html +79 -0
  283. package/tests/pages/button-icons.html +39 -0
  284. package/tests/pages/button_state_mode_1.html +35 -0
  285. package/tests/pages/button_state_mode_2.html +36 -0
  286. package/tests/pages/checkbox-labels.html +116 -0
  287. package/tests/pages/colorpicker-no-3rd-party.html +45 -0
  288. package/tests/pages/colorpicker-use-vanilla-picker.html +52 -0
  289. package/tests/pages/container-attributes.html +51 -0
  290. package/tests/pages/contains.html +39 -0
  291. package/tests/pages/core.html +14 -7
  292. package/tests/pages/datetime.html +78 -0
  293. package/tests/pages/dependentRequired.html +72 -0
  294. package/tests/pages/dependentSchemas.html +53 -0
  295. package/tests/pages/disable-button-in-object-editors.html +57 -0
  296. package/tests/pages/editor-show-validation-errors.html +54 -0
  297. package/tests/pages/enforce-const.html +168 -0
  298. package/tests/pages/error-messages.html +48 -0
  299. package/tests/pages/form-name.html +111 -0
  300. package/tests/pages/grid-strict.html +10 -13
  301. package/tests/pages/grid.html +4 -7
  302. package/tests/pages/if-else.html +58 -0
  303. package/tests/pages/if-then-else-allOf.html +118 -0
  304. package/tests/pages/if-then-else-disable-fields.html +70 -0
  305. package/tests/pages/if-then-else.html +65 -0
  306. package/tests/pages/if-then.html +58 -0
  307. package/tests/pages/inheritance.html +80 -0
  308. package/tests/pages/integer.html +17 -10
  309. package/tests/pages/issues/_template.html +50 -0
  310. package/tests/pages/issues/issue-gh-1133.html +64 -0
  311. package/tests/pages/issues/issue-gh-1158-2.html +189 -0
  312. package/tests/pages/issues/issue-gh-1158.html +50 -0
  313. package/tests/pages/issues/issue-gh-1164.html +71 -0
  314. package/tests/pages/issues/issue-gh-1165.html +63 -0
  315. package/tests/pages/issues/issue-gh-1165.json +8 -0
  316. package/tests/pages/issues/issue-gh-1171.html +39 -0
  317. package/tests/pages/issues/issue-gh-1211.html +1022 -0
  318. package/tests/pages/issues/issue-gh-1233-failing.html +46 -0
  319. package/tests/pages/issues/issue-gh-1233-passing.html +49 -0
  320. package/tests/pages/issues/issue-gh-1257.html +77 -0
  321. package/tests/pages/issues/issue-gh-1272.html +167 -0
  322. package/tests/pages/issues/issue-gh-1330.html +52 -0
  323. package/tests/pages/issues/issue-gh-1338.html +74 -0
  324. package/tests/pages/issues/issue-gh-1347.html +142 -0
  325. package/tests/pages/issues/issue-gh-1364.html +64 -0
  326. package/tests/pages/issues/issue-gh-1367.html +49 -0
  327. package/tests/pages/issues/issue-gh-1383.html +31 -0
  328. package/tests/pages/issues/issue-gh-1383.json +14 -0
  329. package/tests/pages/issues/issue-gh-1384.html +31 -0
  330. package/tests/pages/issues/issue-gh-1384.json +36 -0
  331. package/tests/pages/issues/issue-gh-1410.html +57 -0
  332. package/tests/pages/issues/issue-gh-1422.html +68 -0
  333. package/tests/pages/issues/issue-gh-1431.html +49 -0
  334. package/tests/pages/issues/issue-gh-1439.html +69 -0
  335. package/tests/pages/issues/issue-gh-1452.html +98 -0
  336. package/tests/pages/issues/issue-gh-1453.html +45 -0
  337. package/tests/pages/issues/issue-gh-1461.html +55 -0
  338. package/tests/pages/issues/issue-gh-1463.html +41 -0
  339. package/tests/pages/issues/issue-gh-1466.html +63 -0
  340. package/tests/pages/issues/issue-gh-1471.html +49 -0
  341. package/tests/pages/issues/issue-gh-1485.html +59 -0
  342. package/tests/pages/issues/issue-gh-1491.html +59 -0
  343. package/tests/pages/issues/issue-gh-1525.html +62 -0
  344. package/tests/pages/issues/issue-gh-1536.html +55 -0
  345. package/tests/pages/issues/issue-gh-1538.html +56 -0
  346. package/tests/pages/issues/issue-gh-1541.html +51 -0
  347. package/tests/pages/issues/issue-gh-1541.json +9 -0
  348. package/tests/pages/issues/issue-gh-1559.html +68 -0
  349. package/tests/pages/issues/issue-gh-1562.html +170 -0
  350. package/tests/pages/issues/issue-gh-1586.html +48 -0
  351. package/tests/pages/issues/issue-gh-1636.html +52 -0
  352. package/tests/pages/issues/issue-gh-795.html +58 -0
  353. package/tests/pages/issues/issue-gh-810.html +149 -0
  354. package/tests/pages/issues/issue-gh-812.html +113 -0
  355. package/tests/pages/issues/issue-gh-823-meta-schema.html +35 -0
  356. package/tests/pages/issues/issue-gh-848.html +81 -0
  357. package/tests/pages/keep_only_existing_values.html +81 -0
  358. package/tests/pages/load-events.html +61 -0
  359. package/tests/pages/maxContains.html +40 -0
  360. package/tests/pages/meta-schema.html +793 -0
  361. package/tests/pages/meta_schema.json +740 -0
  362. package/tests/pages/minContains.html +40 -0
  363. package/tests/pages/number.html +53 -6
  364. package/tests/pages/object-case-sensitive-property-search-false.html +42 -0
  365. package/tests/pages/object-case-sensitive-property-search-true.html +42 -0
  366. package/tests/pages/object-no-additional-properties.html +68 -0
  367. package/tests/pages/object-no-duplicated-id.html +70 -0
  368. package/tests/pages/object-required-properties.html +56 -20
  369. package/tests/pages/object-show-opt-in.html +111 -0
  370. package/tests/pages/object-with-dependencies-array.html +58 -0
  371. package/tests/pages/object-with-dependencies.html +62 -0
  372. package/tests/pages/object.html +5 -3
  373. package/tests/pages/oneof-2.html +91 -0
  374. package/tests/pages/oneof.html +105 -0
  375. package/tests/pages/opt-in-widget.html +134 -0
  376. package/tests/pages/option-dependencies.html +107 -0
  377. package/tests/pages/option-no_default_values.html +60 -0
  378. package/tests/pages/per-editor-options.html +44 -0
  379. package/tests/pages/placeholder-options.html +57 -0
  380. package/tests/pages/programmatic-changes.html +121 -0
  381. package/tests/pages/prompt-paste-max-length-reached.html +51 -0
  382. package/tests/pages/purify.html +66 -0
  383. package/tests/pages/range.html +62 -0
  384. package/tests/pages/read-only.html +60 -8
  385. package/tests/pages/ready.html +44 -0
  386. package/tests/pages/references.html +168 -0
  387. package/tests/pages/remove-false-properties.html +85 -0
  388. package/tests/pages/select-values.html +91 -0
  389. package/tests/pages/select.html +4 -3
  390. package/tests/pages/show-validation-errors.html +73 -0
  391. package/tests/pages/starrating.html +86 -0
  392. package/tests/pages/stepper-manual.html +59 -0
  393. package/tests/pages/stepper.html +61 -0
  394. package/tests/pages/string-ace-editor.html +7 -3
  395. package/tests/pages/string-cleave.html +48 -0
  396. package/tests/pages/string-custom-attributes.html +9 -6
  397. package/tests/pages/string-formats.html +54 -0
  398. package/tests/pages/string-formats2.html +59 -0
  399. package/tests/pages/{array-move-events.html → string-jodit-editor.html} +21 -29
  400. package/tests/pages/string-sceditor.html +9 -7
  401. package/tests/pages/string-simplemde-editor.html +83 -0
  402. package/tests/pages/switcher-option.html +69 -0
  403. package/tests/pages/table.html +4 -2
  404. package/tests/pages/tabs.html +1 -1
  405. package/tests/pages/themes.html +517 -0
  406. package/tests/pages/title-hidden.html +75 -0
  407. package/tests/pages/translate-property.html +248 -0
  408. package/tests/pages/urn.html +98 -0
  409. package/tests/pages/use-name-attributes.html +207 -0
  410. package/tests/pages/uuid.html +113 -0
  411. package/tests/pages/validation-messages.json +705 -0
  412. package/tests/pages/validation.html +20 -730
  413. package/tests/unit/.eslintrc +8 -0
  414. package/tests/unit/core.spec.js +320 -0
  415. package/tests/unit/defaults.spec.js +40 -0
  416. package/tests/unit/editor.spec.js +172 -0
  417. package/tests/unit/editors/array.spec.js +87 -0
  418. package/tests/unit/editors/object.spec.js +81 -0
  419. package/tests/unit/editors/table.spec.js +93 -0
  420. package/tests/unit/readme.md +35 -0
  421. package/tests/unit/schemaloader.spec.js +576 -0
  422. package/tests/unit/validator.spec.js +104 -0
  423. package/tests/unit/validators/ip-validator.spec.js +62 -0
  424. package/Gruntfile.js +0 -228
  425. package/dist/css/jsoneditor.min.css +0 -1
  426. package/dist/jsoneditor.js.map +0 -1
  427. package/dist/jsoneditor.min.js +0 -19
  428. package/dist/jsoneditor.min.js.map +0 -1
  429. package/src/class.js +0 -68
  430. package/src/editors/rating.js +0 -152
  431. package/src/ie9.js +0 -51
  432. package/src/intro.js +0 -23
  433. package/src/jquery.js +0 -64
  434. package/src/outro.js +0 -2
  435. package/src/themes/jsoneditor.barebones-theme.js +0 -60
@@ -1,1261 +1,1383 @@
1
- JSONEditor.defaults.editors.object = JSONEditor.AbstractEditor.extend({
2
- getDefault: function() {
3
- return $extend({},this.schema["default"] || {});
4
- },
5
- getChildEditors: function() {
6
- return this.editors;
7
- },
8
- register: function() {
9
- this._super();
10
- if(this.editors) {
11
- for(var i in this.editors) {
12
- if(!this.editors.hasOwnProperty(i)) continue;
13
- this.editors[i].register();
14
- }
1
+ import { AbstractEditor } from '../editor.js'
2
+ import { extend, hasOwnProperty, trigger } from '../utilities.js'
3
+ import rules from './object.css.js'
4
+
5
+ export class ObjectEditor extends AbstractEditor {
6
+ constructor (options, defaults, depth) {
7
+ super(options, defaults)
8
+ this.currentDepth = depth
9
+ }
10
+
11
+ getChildEditors () {
12
+ return this.editors
13
+ }
14
+
15
+ register () {
16
+ super.register()
17
+ if (this.editors) {
18
+ Object.values(this.editors).forEach(e => e.register())
15
19
  }
16
- },
17
- unregister: function() {
18
- this._super();
19
- if(this.editors) {
20
- for(var i in this.editors) {
21
- if(!this.editors.hasOwnProperty(i)) continue;
22
- this.editors[i].unregister();
23
- }
20
+ }
21
+
22
+ unregister () {
23
+ super.unregister()
24
+ if (this.editors) {
25
+ Object.values(this.editors).forEach(e => e.unregister())
24
26
  }
25
- },
26
- getNumColumns: function() {
27
- return Math.max(Math.min(12,this.maxwidth),3);
28
- },
29
- enable: function() {
30
- if(!this.always_disabled) {
31
- if(this.editjson_button) this.editjson_button.disabled = false;
32
- if(this.addproperty_button) this.addproperty_button.disabled = false;
33
-
34
- this._super();
35
- if(this.editors) {
36
- for(var i in this.editors) {
37
- if(!this.editors.hasOwnProperty(i)) continue;
38
- this.editors[i].enable();
39
- this.editors[i].optInCheckbox.disabled = false;
40
- }
27
+ }
28
+
29
+ getNumColumns () {
30
+ return Math.max(Math.min(12, this.maxwidth), 3)
31
+ }
32
+
33
+ enable () {
34
+ if (!this.always_disabled) {
35
+ if (this.editjson_control) this.editjson_control.disabled = false
36
+ if (this.addproperty_button) this.addproperty_button.disabled = false
37
+
38
+ super.enable()
39
+ if (this.editors) {
40
+ Object.values(this.editors).forEach(e => {
41
+ if (e.isActive() || e.isUiOnly) {
42
+ e.enable()
43
+ }
44
+ if (e.optInCheckbox) {
45
+ e.optInCheckbox.disabled = false
46
+ }
47
+ })
41
48
  }
42
49
  }
43
- },
44
- disable: function(always_disabled) {
45
- if(always_disabled) this.always_disabled = true;
46
- if(this.editjson_button) this.editjson_button.disabled = true;
47
- if(this.addproperty_button) this.addproperty_button.disabled = true;
48
- this.hideEditJSON();
49
-
50
- this._super();
51
- if(this.editors) {
52
- for(var i in this.editors) {
53
- if(!this.editors.hasOwnProperty(i)) continue;
54
- this.editors[i].disable(always_disabled);
55
- this.editors[i].optInCheckbox.disabled = true;
56
- }
50
+ }
51
+
52
+ disable (alwaysDisabled) {
53
+ if (alwaysDisabled) this.always_disabled = true
54
+ if (this.editjson_control) this.editjson_control.disabled = true
55
+ if (this.addproperty_button) this.addproperty_button.disabled = true
56
+ this.hideEditJSON()
57
+
58
+ super.disable()
59
+ if (this.editors) {
60
+ Object.values(this.editors).forEach(e => {
61
+ if (e.isActive() || e.isUiOnly) {
62
+ e.disable(alwaysDisabled)
63
+ }
64
+ e.optInCheckbox.disabled = true
65
+ })
57
66
  }
58
- },
59
- layoutEditors: function() {
60
- var self = this, i, j;
61
-
62
- if(!this.row_container) return;
63
-
64
- // Sort editors by propertyOrder
65
- this.property_order = Object.keys(this.editors);
66
- this.property_order = this.property_order.sort(function(a,b) {
67
- var ordera = self.editors[a].schema.propertyOrder;
68
- var orderb = self.editors[b].schema.propertyOrder;
69
- if(typeof ordera !== "number") ordera = 1000;
70
- if(typeof orderb !== "number") orderb = 1000;
71
-
72
- return ordera - orderb;
73
- });
74
-
75
- var container;
76
- var isCategoriesFormat = (this.format === 'categories');
77
- var rows = [];
78
- var key = null;
79
- var editor = null;
80
- var row;
81
-
82
- if(this.format === 'grid-strict') {
83
- var rowIndex = 0;
84
- row = [];
85
-
86
- $each(this.property_order, function(j,key) {
87
- var editor = self.editors[key];
67
+ }
68
+
69
+ layoutEditors () {
70
+ let i; let j
71
+
72
+ if (!this.row_container) return
73
+
74
+ /* Sort editors by propertyOrder */
75
+ this.property_order = Object.keys(this.editors)
76
+ this.property_order = this.property_order.sort((a, b) => {
77
+ let ordera = this.editors[a].schema.propertyOrder
78
+ let orderb = this.editors[b].schema.propertyOrder
79
+ if (typeof ordera !== 'number') ordera = 1000
80
+ if (typeof orderb !== 'number') orderb = 1000
81
+
82
+ return ordera - orderb
83
+ })
84
+
85
+ let container
86
+ const isCategoriesFormat = (this.format === 'categories')
87
+ const rows = []
88
+ let key = null
89
+ let editor = null
90
+ let row
91
+
92
+ if (this.format === 'grid-strict') {
93
+ let rowIndex = 0
94
+ row = []
95
+
96
+ this.property_order.forEach(key => {
97
+ const editor = this.editors[key]
88
98
  if (editor.property_removed) {
89
- return;
99
+ return
100
+ }
101
+ const width = editor.options.hidden ? 0 : (editor.options.grid_columns || editor.getNumColumns())
102
+ const offset = editor.options.hidden ? 0 : (editor.options.grid_offset || 0)
103
+ const gridBreak = editor.options.hidden ? false : (editor.options.grid_break || false)
104
+ const height = editor.options.hidden ? 0 : editor.container.offsetHeight
105
+
106
+ const column = {
107
+ key,
108
+ width,
109
+ offset,
110
+ height
90
111
  }
91
- var width = editor.options.hidden ? 0 : (editor.options.grid_columns || editor.getNumColumns());
92
- var offset = editor.options.hidden ? 0 : (editor.options.grid_offset || 0);
93
- var gridBreak = editor.options.hidden ? false : (editor.options.grid_break || false);
94
- var height = editor.options.hidden ? 0 : editor.container.offsetHeight;
95
-
96
- var column = {
97
- key: key,
98
- width: width,
99
- offset: offset,
100
- height: height
101
- };
102
112
 
103
- row.push(column);
113
+ row.push(column)
104
114
 
105
- rows[rowIndex] = row;
115
+ rows[rowIndex] = row
106
116
 
107
117
  if (gridBreak) {
108
- rowIndex++;
109
- row = [];
118
+ rowIndex++
119
+ row = []
110
120
  }
111
- });
121
+ })
112
122
 
113
- // layout hasn't changed
114
- if (this.layout === JSON.stringify(rows)) return false;
115
- this.layout = JSON.stringify(rows);
123
+ /* layout hasn't changed */
124
+ if (this.layout === JSON.stringify(rows)) return false
125
+ this.layout = JSON.stringify(rows)
116
126
 
117
- // Layout the form
118
- container = document.createElement('div');
127
+ /* Layout the form */
128
+ container = document.createElement('div')
119
129
  for (i = 0; i < rows.length; i++) {
120
- row = this.theme.getGridRow();
121
- container.appendChild(row);
130
+ row = this.theme.getGridRow()
131
+ container.appendChild(row)
122
132
  for (j = 0; j < rows[i].length; j++) {
123
- key = rows[i][j].key;
124
- editor = this.editors[key];
133
+ key = rows[i][j].key
134
+ editor = this.editors[key]
125
135
  if (editor.options.hidden) {
126
- editor.container.style.display = 'none';
136
+ editor.container.style.display = 'none'
127
137
  } else {
128
- this.theme.setGridColumnSize(editor.container, rows[i][j].width, rows[i][j].offset);
138
+ this.theme.setGridColumnSize(editor.container, rows[i][j].width, rows[i][j].offset)
129
139
  }
130
- row.appendChild(editor.container);
140
+ row.appendChild(editor.container)
131
141
  }
132
142
  }
133
- } else if(this.format === 'grid') {
134
- $each(this.property_order, function(j,key) {
135
- var editor = self.editors[key];
136
- if(editor.property_removed) return;
137
- var found = false;
138
- var width = editor.options.hidden? 0 : (editor.options.grid_columns || editor.getNumColumns());
139
- var height = editor.options.hidden? 0 : editor.container.offsetHeight;
140
- // See if the editor will fit in any of the existing rows first
141
- for(var i=0; i<rows.length; i++) {
142
- // If the editor will fit in the row horizontally
143
- if(rows[i].width + width <= 12) {
144
- // If the editor is close to the other elements in height
145
- // i.e. Don't put a really tall editor in an otherwise short row or vice versa
146
- if(!height || (rows[i].minh*0.5 < height && rows[i].maxh*2 > height)) {
147
- found = i;
143
+ } else if (this.format === 'grid') {
144
+ this.property_order.forEach(key => {
145
+ const editor = this.editors[key]
146
+ if (editor.property_removed) return
147
+ let found = false
148
+ const width = editor.options.hidden ? 0 : (editor.options.grid_columns || editor.getNumColumns())
149
+ const height = editor.options.hidden ? 0 : editor.container.offsetHeight
150
+ /* See if the editor will fit in any of the existing rows first */
151
+ for (let i = 0; i < rows.length; i++) {
152
+ /* If the editor will fit in the row horizontally */
153
+ if (rows[i].width + width <= 12) {
154
+ /* If the editor is close to the other elements in height */
155
+ /* i.e. Don't put a really tall editor in an otherwise short row or vice versa */
156
+ if (!height || (rows[i].minh * 0.5 < height && rows[i].maxh * 2 > height)) {
157
+ found = i
148
158
  }
149
159
  }
150
160
  }
151
161
 
152
- // If there isn't a spot in any of the existing rows, start a new row
153
- if(found === false) {
162
+ /* If there isn't a spot in any of the existing rows, start a new row */
163
+ if (found === false) {
154
164
  rows.push({
155
165
  width: 0,
156
166
  minh: 999999,
157
167
  maxh: 0,
158
168
  editors: []
159
- });
160
- found = rows.length-1;
169
+ })
170
+ found = rows.length - 1
161
171
  }
162
172
 
163
173
  rows[found].editors.push({
164
- key: key,
165
- //editor: editor,
166
- width: width,
167
- height: height
168
- });
169
- rows[found].width += width;
170
- rows[found].minh = Math.min(rows[found].minh,height);
171
- rows[found].maxh = Math.max(rows[found].maxh,height);
172
- });
173
-
174
- // Make almost full rows width 12
175
- // Do this by increasing all editors' sizes proprotionately
176
- // Any left over space goes to the biggest editor
177
- // Don't touch rows with a width of 6 or less
178
- for(i=0; i<rows.length; i++) {
179
- if(rows[i].width < 12) {
180
- var biggest = false;
181
- var new_width = 0;
182
- for(j=0; j<rows[i].editors.length; j++) {
183
- if(biggest === false) biggest = j;
184
- else if(rows[i].editors[j].width > rows[i].editors[biggest].width) biggest = j;
185
- rows[i].editors[j].width *= 12/rows[i].width;
186
- rows[i].editors[j].width = Math.floor(rows[i].editors[j].width);
187
- new_width += rows[i].editors[j].width;
174
+ key,
175
+ /* editor: editor, */
176
+ width,
177
+ height
178
+ })
179
+ rows[found].width += width
180
+ rows[found].minh = Math.min(rows[found].minh, height)
181
+ rows[found].maxh = Math.max(rows[found].maxh, height)
182
+ })
183
+
184
+ /* Make almost full rows width 12 */
185
+ /* Do this by increasing all editors' sizes proprotionately */
186
+ /* Any left over space goes to the biggest editor */
187
+ /* Don't touch rows with a width of 6 or less */
188
+ for (i = 0; i < rows.length; i++) {
189
+ if (rows[i].width < 12) {
190
+ let biggest = false
191
+ let newWidth = 0
192
+ for (j = 0; j < rows[i].editors.length; j++) {
193
+ if (biggest === false) biggest = j
194
+ else if (rows[i].editors[j].width > rows[i].editors[biggest].width) biggest = j
195
+ rows[i].editors[j].width *= 12 / rows[i].width
196
+ rows[i].editors[j].width = Math.floor(rows[i].editors[j].width)
197
+ newWidth += rows[i].editors[j].width
188
198
  }
189
- if(new_width < 12) rows[i].editors[biggest].width += 12-new_width;
190
- rows[i].width = 12;
199
+ if (newWidth < 12) rows[i].editors[biggest].width += 12 - newWidth
200
+ rows[i].width = 12
191
201
  }
192
202
  }
193
203
 
194
- // layout hasn't changed
195
- if(this.layout === JSON.stringify(rows)) return false;
196
- this.layout = JSON.stringify(rows);
197
-
198
- // Layout the form
199
- container = document.createElement('div');
200
- for(i=0; i<rows.length; i++) {
201
- row = this.theme.getGridRow();
202
- container.appendChild(row);
203
- for(j=0; j<rows[i].editors.length; j++) {
204
- key = rows[i].editors[j].key;
205
- editor = this.editors[key];
206
-
207
- if(editor.options.hidden) editor.container.style.display = 'none';
208
- else this.theme.setGridColumnSize(editor.container,rows[i].editors[j].width);
209
- row.appendChild(editor.container);
204
+ /* layout hasn't changed */
205
+ if (this.layout === JSON.stringify(rows)) return false
206
+ this.layout = JSON.stringify(rows)
207
+
208
+ /* Layout the form */
209
+ container = document.createElement('div')
210
+ for (i = 0; i < rows.length; i++) {
211
+ row = this.theme.getGridRow()
212
+ container.appendChild(row)
213
+ for (j = 0; j < rows[i].editors.length; j++) {
214
+ key = rows[i].editors[j].key
215
+ editor = this.editors[key]
216
+
217
+ if (editor.options.hidden) editor.container.style.display = 'none'
218
+ else this.theme.setGridColumnSize(editor.container, rows[i].editors[j].width)
219
+ row.appendChild(editor.container)
210
220
  }
211
221
  }
212
- }
213
- // Normal layout
214
- else {
215
- container = document.createElement('div');
216
-
217
- if(isCategoriesFormat) {
218
- //A container for properties not object nor arrays
219
- var containerSimple = document.createElement('div');
220
- //This will be the place to (re)build tabs and panes
221
- //tabs_holder has 2 childs, [0]: ul.nav.nav-tabs and [1]: div.tab-content
222
- var newTabs_holder = this.theme.getTopTabHolder(this.schema.title);
223
- //child [1] of previous, stores panes
224
- var newTabPanesContainer = this.theme.getTopTabContentHolder(newTabs_holder);
225
-
226
- $each(this.property_order, function(i,key){
227
- var editor = self.editors[key];
228
- if(editor.property_removed) return;
229
- var aPane = self.theme.getTabContent();
230
- var isObjOrArray = editor.schema && (editor.schema.type === "object" || editor.schema.type === "array");
231
- //mark the pane
232
- aPane.isObjOrArray = isObjOrArray;
233
- var gridRow = self.theme.getGridRow();
234
-
235
- //this happens with added properties, they don't have a tab
236
- if(!editor.tab){
237
- //Pass the pane which holds the editor
238
- if(typeof self.basicPane === 'undefined'){
239
- //There is no basicPane yet, so aPane will be it
240
- self.addRow(editor,newTabs_holder, aPane);
241
- }
242
- else {
243
- self.addRow(editor,newTabs_holder, self.basicPane);
222
+ /* Normal layout */
223
+ } else {
224
+ container = document.createElement('div')
225
+
226
+ if (isCategoriesFormat) {
227
+ /* A container for properties not object nor arrays */
228
+ const containerSimple = document.createElement('div')
229
+ /* This will be the place to (re)build tabs and panes */
230
+ /* tabs_holder has 2 childs, [0]: ul.nav.nav-tabs and [1]: div.tab-content */
231
+ const newTabsHolder = this.theme.getTopTabHolder(this.translateProperty(this.schema.title))
232
+ /* child [1] of previous, stores panes */
233
+ const newTabPanesContainer = this.theme.getTopTabContentHolder(newTabsHolder)
234
+
235
+ this.property_order.forEach(key => {
236
+ const editor = this.editors[key]
237
+ if (editor.property_removed) return
238
+ const aPane = this.theme.getTabContent()
239
+ const isObjOrArray = editor.schema && (editor.schema.type === 'object' || editor.schema.type === 'array')
240
+ /* mark the pane */
241
+ aPane.isObjOrArray = isObjOrArray
242
+ const gridRow = this.theme.getGridRow()
243
+
244
+ /* this happens with added properties, they don't have a tab */
245
+ if (!editor.tab) {
246
+ /* Pass the pane which holds the editor */
247
+ if (typeof this.basicPane === 'undefined') {
248
+ /* There is no basicPane yet, so aPane will be it */
249
+ this.addRow(editor, newTabsHolder, aPane)
250
+ } else {
251
+ this.addRow(editor, newTabsHolder, this.basicPane)
244
252
  }
245
253
  }
246
254
 
247
- aPane.id = self.getValidId(editor.tab_text.textContent);
248
-
249
- //For simple properties, add them on the same panel (Basic)
250
- if(!isObjOrArray){
251
- containerSimple.appendChild(gridRow);
252
- //There are already some panes
253
- if(newTabPanesContainer.childElementCount > 0){
254
- //If first pane is object or array, insert before a simple pane
255
- if(newTabPanesContainer.firstChild.isObjOrArray){
256
- //Append pane for simple properties
257
- aPane.appendChild(containerSimple);
258
- newTabPanesContainer.insertBefore(aPane,newTabPanesContainer.firstChild);
259
- //Add "Basic" tab
260
- self.theme.insertBasicTopTab(editor.tab,newTabs_holder);
261
- //newTabs_holder.firstChild.insertBefore(editor.tab,newTabs_holder.firstChild.firstChild);
262
- //Update the basicPane
263
- editor.basicPane = aPane;
255
+ aPane.id = this.getValidId(editor.tab_text.textContent)
256
+
257
+ /* For simple properties, add them on the same panel (Basic) */
258
+ if (!isObjOrArray) {
259
+ containerSimple.appendChild(gridRow)
260
+ /* There are already some panes */
261
+ if (newTabPanesContainer.childElementCount > 0) {
262
+ /* If first pane is object or array, insert before a simple pane */
263
+ if (newTabPanesContainer.firstChild.isObjOrArray) {
264
+ /* Append pane for simple properties */
265
+ aPane.appendChild(containerSimple)
266
+ newTabPanesContainer.insertBefore(aPane, newTabPanesContainer.firstChild)
267
+ /* Add "Basic" tab */
268
+ this.theme.insertBasicTopTab(editor.tab, newTabsHolder)
269
+ /* newTabs_holder.firstChild.insertBefore(editor.tab,newTabs_holder.firstChild.firstChild); */
270
+ /* Update the basicPane */
271
+ editor.basicPane = aPane
272
+ } else {
273
+ /* We already have a first "Basic" pane, just add the new property to it, so */
274
+ /* do nothing; */
264
275
  }
265
- else {
266
- //We already have a first "Basic" pane, just add the new property to it, so
267
- //do nothing;
268
- }
269
- }
270
- //There is no pane, so add the first (simple) pane
271
- else {
272
- //Append pane for simple properties
273
- aPane.appendChild(containerSimple);
274
- newTabPanesContainer.appendChild(aPane);
275
- //Add "Basic" tab
276
- //newTabs_holder.firstChild.appendChild(editor.tab);
277
- self.theme.addTopTab(newTabs_holder,editor.tab);
278
- //Update the basicPane
279
- editor.basicPane = aPane;
276
+ /* There is no pane, so add the first (simple) pane */
277
+ } else {
278
+ /* Append pane for simple properties */
279
+ aPane.appendChild(containerSimple)
280
+ newTabPanesContainer.appendChild(aPane)
281
+ /* Add "Basic" tab */
282
+ /* newTabs_holder.firstChild.appendChild(editor.tab); */
283
+ this.theme.addTopTab(newTabsHolder, editor.tab)
284
+ /* Update the basicPane */
285
+ editor.basicPane = aPane
280
286
  }
281
- }
282
- //Objects and arrays earn it's own panes
283
- else {
284
- aPane.appendChild(gridRow);
285
- newTabPanesContainer.appendChild(aPane);
286
- //newTabs_holder.firstChild.appendChild(editor.tab);
287
- self.theme.addTopTab(newTabs_holder,editor.tab);
287
+ /* Objects and arrays earn their own panes */
288
+ } else {
289
+ aPane.appendChild(gridRow)
290
+ newTabPanesContainer.appendChild(aPane)
291
+ /* newTabs_holder.firstChild.appendChild(editor.tab); */
292
+ this.theme.addTopTab(newTabsHolder, editor.tab)
288
293
  }
289
294
 
290
- if(editor.options.hidden) editor.container.style.display = 'none';
291
- else self.theme.setGridColumnSize(editor.container,12);
292
- //Now, add the property editor to the row
293
- gridRow.appendChild(editor.container);
294
- //Update the rowPane (same as self.rows[x].rowPane)
295
- editor.rowPane = aPane;
295
+ if (editor.options.hidden) editor.container.style.display = 'none'
296
+ else this.theme.setGridColumnSize(editor.container, 12)
297
+ /* Now, add the property editor to the row */
298
+ gridRow.appendChild(editor.container)
299
+ /* Update the rowPane (same as this.rows[x].rowPane) */
300
+ editor.rowPane = aPane
301
+ })
296
302
 
297
- });
298
-
299
- //Erase old panes
303
+ /* Erase old panes */
300
304
  while (this.tabPanesContainer.firstChild) {
301
- this.tabPanesContainer.removeChild(this.tabPanesContainer.firstChild);
305
+ this.tabPanesContainer.removeChild(this.tabPanesContainer.firstChild)
302
306
  }
303
307
 
304
- //Erase old tabs and set the new ones
305
- var parentTabs_holder = this.tabs_holder.parentNode;
306
- parentTabs_holder.removeChild(parentTabs_holder.firstChild);
307
- parentTabs_holder.appendChild(newTabs_holder);
308
+ /* Erase old tabs and set the new ones */
309
+ const parentTabsHolder = this.tabs_holder.parentNode
310
+ parentTabsHolder.removeChild(parentTabsHolder.firstChild)
311
+ parentTabsHolder.appendChild(newTabsHolder)
308
312
 
309
- this.tabPanesContainer = newTabPanesContainer;
310
- this.tabs_holder = newTabs_holder;
313
+ this.tabPanesContainer = newTabPanesContainer
314
+ this.tabs_holder = newTabsHolder
311
315
 
312
- //Activate the first tab
313
- var firstTab = this.theme.getFirstTab(this.tabs_holder);
314
- if(firstTab){
315
- $trigger(firstTab,'click');
316
+ /* Activate the first tab */
317
+ const firstTab = this.theme.getFirstTab(this.tabs_holder)
318
+ if (firstTab) {
319
+ trigger(firstTab, 'click')
316
320
  }
317
- return;
318
- }
319
- //Normal layout
320
- else {
321
- $each(this.property_order, function(i,key) {
322
- var editor = self.editors[key];
323
- if(editor.property_removed) return;
324
- row = self.theme.getGridRow();
325
- container.appendChild(row);
326
-
327
- if(editor.options.hidden) editor.container.style.display = 'none';
328
- else self.theme.setGridColumnSize(editor.container,12);
329
- row.appendChild(editor.container);
330
- });
321
+ return
322
+ /* Normal layout */
331
323
  }
324
+ this.property_order.forEach(key => {
325
+ const editor = this.editors[key]
326
+ if (editor.property_removed) return
327
+ row = this.theme.getGridRow()
328
+ container.appendChild(row)
329
+
330
+ if (editor.options.hidden) editor.container.style.display = 'none'
331
+ else this.theme.setGridColumnSize(editor.container, 12)
332
+ row.appendChild(editor.container)
333
+ })
332
334
  }
333
- //for grid and normal layout
335
+ /* for grid and normal layout */
334
336
  while (this.row_container.firstChild) {
335
- this.row_container.removeChild(this.row_container.firstChild);
337
+ this.row_container.removeChild(this.row_container.firstChild)
336
338
  }
337
- this.row_container.appendChild(container);
338
- },
339
- getPropertySchema: function(key) {
340
- // Schema declared directly in properties
341
- var schema = this.schema.properties[key] || {};
342
- schema = $extend({},schema);
343
- var matched = this.schema.properties[key]? true : false;
344
-
345
- // Any matching patternProperties should be merged in
346
- if(this.schema.patternProperties) {
347
- for(var i in this.schema.patternProperties) {
348
- if(!this.schema.patternProperties.hasOwnProperty(i)) continue;
349
- var regex = new RegExp(i);
350
- if(regex.test(key)) {
351
- schema.allOf = schema.allOf || [];
352
- schema.allOf.push(this.schema.patternProperties[i]);
353
- matched = true;
339
+ this.row_container.appendChild(container)
340
+ }
341
+
342
+ getPropertySchema (key) {
343
+ /* Schema declared directly in properties */
344
+ let schema = this.schema.properties[key] || {}
345
+ schema = extend({}, schema)
346
+ let matched = !!this.schema.properties[key]
347
+
348
+ /* Any matching patternProperties should be merged in */
349
+ if (this.schema.patternProperties) {
350
+ Object.keys(this.schema.patternProperties).forEach(i => {
351
+ const regex = new RegExp(i)
352
+ if (regex.test(key)) {
353
+ schema.allOf = schema.allOf || []
354
+ schema.allOf.push(this.schema.patternProperties[i])
355
+ matched = true
354
356
  }
355
- }
357
+ })
356
358
  }
357
359
 
358
- // Hasn't matched other rules, use additionalProperties schema
359
- if(!matched && this.schema.additionalProperties && typeof this.schema.additionalProperties === "object") {
360
- schema = $extend({},this.schema.additionalProperties);
360
+ /* Hasn't matched other rules, use additionalProperties schema */
361
+ if (!matched && this.schema.additionalProperties && typeof this.schema.additionalProperties === 'object') {
362
+ schema = extend({}, this.schema.additionalProperties)
361
363
  }
362
364
 
363
- return schema;
364
- },
365
- preBuild: function() {
366
- this._super();
365
+ return schema
366
+ }
367
+
368
+ preBuild () {
369
+ super.preBuild()
367
370
 
368
- this.editors = {};
369
- this.cached_editors = {};
370
- var self = this;
371
+ this.editors = {}
372
+ this.cached_editors = {}
371
373
 
372
- this.format = this.options.layout || this.options.object_layout || this.schema.format || this.jsoneditor.options.object_layout || 'normal';
374
+ this.format = this.options.layout || this.options.object_layout || this.schema.format || this.jsoneditor.options.object_layout || 'normal'
373
375
 
374
- this.schema.properties = this.schema.properties || {};
376
+ this.schema.properties = this.schema.properties || {}
375
377
 
376
- this.minwidth = 0;
377
- this.maxwidth = 0;
378
+ this.minwidth = 0
379
+ this.maxwidth = 0
378
380
 
379
- // If the object should be rendered as a table row
380
- if(this.options.table_row) {
381
- $each(this.schema.properties, function(key,schema) {
382
- var editor = self.jsoneditor.getEditorClass(schema);
383
- self.editors[key] = self.jsoneditor.createEditor(editor,{
384
- jsoneditor: self.jsoneditor,
385
- schema: schema,
386
- path: self.path+'.'+key,
387
- parent: self,
381
+ /* If the object should be rendered as a table row */
382
+ if (this.options.table_row) {
383
+ Object.entries(this.schema.properties).forEach(([key, schema]) => {
384
+ const editor = this.jsoneditor.getEditorClass(schema)
385
+ this.editors[key] = this.jsoneditor.createEditor(editor, {
386
+ jsoneditor: this.jsoneditor,
387
+ schema,
388
+ path: `${this.path}.${key}`,
389
+ parent: this,
388
390
  compact: true,
389
391
  required: true
390
- });
391
- self.editors[key].preBuild();
392
-
393
- var width = self.editors[key].options.hidden? 0 : (self.editors[key].options.grid_columns || self.editors[key].getNumColumns());
394
-
395
- self.minwidth += width;
396
- self.maxwidth += width;
397
- });
398
- this.no_link_holder = true;
399
- }
400
- // If the object should be rendered as a table
401
- else if(this.options.table) {
402
- // TODO: table display format
403
- throw "Not supported yet";
404
- }
405
- // If the object should be rendered as a div
406
- else {
407
- if(!this.schema.defaultProperties) {
408
- if(this.jsoneditor.options.display_required_only || this.options.display_required_only) {
409
- this.schema.defaultProperties = [];
410
- $each(this.schema.properties, function(k,s) {
411
- if(self.isRequired({key: k, schema: s})) {
412
- self.schema.defaultProperties.push(k);
413
- }
414
- });
415
- }
416
- else {
417
- self.schema.defaultProperties = Object.keys(self.schema.properties);
392
+ }, this.currentDepth + 1)
393
+ this.editors[key].preBuild()
394
+
395
+ const width = this.editors[key].options.hidden ? 0 : (this.editors[key].options.grid_columns || this.editors[key].getNumColumns())
396
+
397
+ this.minwidth += width
398
+ this.maxwidth += width
399
+ })
400
+ this.no_link_holder = true
401
+ /* If the object should be rendered as a table */
402
+ } else if (this.options.table) {
403
+ /* TODO: table display format */
404
+ throw new Error('Not supported yet')
405
+ /* If the object should be rendered as a div */
406
+ } else {
407
+ if (!this.schema.defaultProperties) {
408
+ if (this.jsoneditor.options.display_required_only || this.options.display_required_only) {
409
+ this.schema.defaultProperties = Object.keys(this.schema.properties).filter(k => this.isRequiredObject({ key: k, schema: this.schema.properties[k] }))
410
+ } else {
411
+ this.schema.defaultProperties = Object.keys(this.schema.properties)
418
412
  }
419
413
  }
420
414
 
421
- // Increase the grid width to account for padding
422
- self.maxwidth += 1;
415
+ /* Increase the grid width to account for padding */
416
+ this.maxwidth += 1
423
417
 
424
- $each(this.schema.defaultProperties, function(i,key) {
425
- self.addObjectProperty(key, true);
418
+ /* Check for array (eg. meta-schema options is an object) */
419
+ if (Array.isArray(this.schema.defaultProperties)) {
420
+ this.schema.defaultProperties.forEach(key => {
421
+ this.addObjectProperty(key, true)
426
422
 
427
- if(self.editors[key]) {
428
- self.minwidth = Math.max(self.minwidth,(self.editors[key].options.grid_columns || self.editors[key].getNumColumns()));
429
- self.maxwidth += (self.editors[key].options.grid_columns || self.editors[key].getNumColumns());
430
- }
431
- });
423
+ if (this.editors[key]) {
424
+ this.minwidth = Math.max(this.minwidth, (this.editors[key].options.grid_columns || this.editors[key].getNumColumns()))
425
+ this.maxwidth += (this.editors[key].options.grid_columns || this.editors[key].getNumColumns())
426
+ }
427
+ })
428
+ }
432
429
  }
433
430
 
434
- // Sort editors by propertyOrder
435
- this.property_order = Object.keys(this.editors);
436
- this.property_order = this.property_order.sort(function(a,b) {
437
- var ordera = self.editors[a].schema.propertyOrder;
438
- var orderb = self.editors[b].schema.propertyOrder;
439
- if(typeof ordera !== "number") ordera = 1000;
440
- if(typeof orderb !== "number") orderb = 1000;
441
-
442
- return ordera - orderb;
443
- });
444
- },
445
- //"Borrow" from arrays code
446
- addTab: function(idx){
447
- var self = this;
448
- var isObjOrArray = self.rows[idx].schema && (self.rows[idx].schema.type === "object" || self.rows[idx].schema.type === "array");
449
- if(self.tabs_holder) {
450
- self.rows[idx].tab_text = document.createElement('span');
451
-
452
- if(!isObjOrArray){
453
- self.rows[idx].tab_text.textContent = (typeof self.schema.basicCategoryTitle === 'undefined') ? "Basic" : self.schema.basicCategoryTitle;
454
- } else {
455
- self.rows[idx].tab_text.textContent = self.rows[idx].getHeaderText();
456
- }
457
- self.rows[idx].tab = self.theme.getTopTab(self.rows[idx].tab_text,this.getValidId(self.rows[idx].tab_text.textContent));
458
- self.rows[idx].tab.addEventListener('click', function(e) {
459
- self.active_tab = self.rows[idx].tab;
460
- self.refreshTabs();
461
- e.preventDefault();
462
- e.stopPropagation();
463
- });
431
+ /* Sort editors by propertyOrder */
432
+ this.property_order = Object.keys(this.editors)
433
+ this.property_order = this.property_order.sort((a, b) => {
434
+ let ordera = this.editors[a].schema.propertyOrder
435
+ let orderb = this.editors[b].schema.propertyOrder
436
+ if (typeof ordera !== 'number') ordera = 1000
437
+ if (typeof orderb !== 'number') orderb = 1000
464
438
 
465
- }
439
+ return ordera - orderb
440
+ })
441
+ }
466
442
 
467
- },
468
- addRow: function(editor, tabHolder, aPane) {
469
- var self = this;
470
- var rowsLen = this.rows.length;
471
- var isObjOrArray = editor.schema.type === "object" || editor.schema.type === "array";
472
-
473
- //Add a row
474
- self.rows[rowsLen] = editor;
475
- //rowPane stores the editor corresponding pane to set the display style when refreshing Tabs
476
- self.rows[rowsLen].rowPane = aPane;
477
-
478
- if(!isObjOrArray){
479
-
480
- //This is the first simple property to be added,
481
- //add a ("Basic") tab for it and save it's row number
482
- if(typeof self.basicTab === "undefined"){
483
- self.addTab(rowsLen);
484
- //Store the index row of the first simple property added
485
- self.basicTab = rowsLen;
486
- self.basicPane = aPane;
487
- self.theme.addTopTab(tabHolder, self.rows[rowsLen].tab);
488
- }
443
+ /* "Borrow" from arrays code */
444
+ addTab (idx) {
445
+ const isObjOrArray = this.rows[idx].schema && (this.rows[idx].schema.type === 'object' || this.rows[idx].schema.type === 'array')
446
+ if (this.tabs_holder) {
447
+ this.rows[idx].tab_text = document.createElement('span')
489
448
 
490
- else {
491
- //Any other simple property gets the same tab (and the same pane) as the first one,
492
- //so, when 'click' event is fired from a row, it gets the correct ("Basic") tab
493
- self.rows[rowsLen].tab = self.rows[self.basicTab].tab;
494
- self.rows[rowsLen].tab_text = self.rows[self.basicTab].tab_text;
495
- self.rows[rowsLen].rowPane = self.rows[self.basicTab].rowPane;
449
+ if (!isObjOrArray) {
450
+ this.rows[idx].tab_text.textContent = (typeof this.schema.basicCategoryTitle === 'undefined') ? 'Basic' : this.schema.basicCategoryTitle
451
+ } else {
452
+ this.rows[idx].tab_text.textContent = this.rows[idx].getHeaderText()
496
453
  }
454
+ this.rows[idx].tab = this.theme.getTopTab(this.rows[idx].tab_text, this.getValidId(this.rows[idx].tab_text.textContent))
455
+ this.rows[idx].tab.addEventListener('click', (e) => {
456
+ this.active_tab = this.rows[idx].tab
457
+ this.refreshTabs()
458
+ e.preventDefault()
459
+ e.stopPropagation()
460
+ })
497
461
  }
498
- else {
499
- self.addTab(rowsLen);
500
- self.theme.addTopTab(tabHolder, self.rows[rowsLen].tab);
462
+ }
463
+
464
+ addRow (editor, tabHolder, aPane) {
465
+ const rowsLen = this.rows.length
466
+ const isObjOrArray = editor.schema.type === 'object' || editor.schema.type === 'array'
467
+
468
+ /* Add a row */
469
+ this.rows[rowsLen] = editor
470
+ /* rowPane stores the editor corresponding pane to set the display style when refreshing Tabs */
471
+ this.rows[rowsLen].rowPane = aPane
472
+
473
+ if (!isObjOrArray) {
474
+ /* This is the first simple property to be added, */
475
+ /* add a ("Basic") tab for it and save it's row number */
476
+ if (typeof this.basicTab === 'undefined') {
477
+ this.addTab(rowsLen)
478
+ /* Store the index row of the first simple property added */
479
+ this.basicTab = rowsLen
480
+ this.basicPane = aPane
481
+ this.theme.addTopTab(tabHolder, this.rows[rowsLen].tab)
482
+ } else {
483
+ /* Any other simple property gets the same tab (and the same pane) as the first one, */
484
+ /* so, when 'click' event is fired from a row, it gets the correct ("Basic") tab */
485
+ this.rows[rowsLen].tab = this.rows[this.basicTab].tab
486
+ this.rows[rowsLen].tab_text = this.rows[this.basicTab].tab_text
487
+ this.rows[rowsLen].rowPane = this.rows[this.basicTab].rowPane
488
+ }
489
+ } else {
490
+ this.addTab(rowsLen)
491
+ this.theme.addTopTab(tabHolder, this.rows[rowsLen].tab)
501
492
  }
502
- },
503
- //Mark the active tab and make visible the corresponding pane, hide others
504
- refreshTabs: function(refresh_headers) {
505
- var self = this;
506
- var basicTabPresent = typeof self.basicTab !== 'undefined';
507
- var basicTabRefreshed = false;
493
+ }
508
494
 
509
- $each(this.rows, function(i,row) {
510
- //If it's an orphan row (some property which has been deleted), return
511
- if(!row.tab || !row.rowPane || !row.rowPane.parentNode) return;
495
+ /* Mark the active tab and make visible the corresponding pane, hide others */
496
+ refreshTabs (refreshHeaders) {
497
+ const basicTabPresent = typeof this.basicTab !== 'undefined'
498
+ let basicTabRefreshed = false
512
499
 
513
- if(basicTabPresent && row.tab == self.rows[self.basicTab].tab && basicTabRefreshed) return;
500
+ this.rows.forEach(row => {
501
+ /* If it's an orphan row (some property which has been deleted), return */
502
+ if (!row.tab || !row.rowPane || !row.rowPane.parentNode) return
514
503
 
515
- if(refresh_headers) {
516
- row.tab_text.textContent = row.getHeaderText();
517
- }
518
- else {
519
- //All rows of simple properties point to the same tab, so refresh just once
520
- if(basicTabPresent && row.tab == self.rows[self.basicTab].tab) basicTabRefreshed = true;
504
+ if (basicTabPresent && row.tab === this.rows[this.basicTab].tab && basicTabRefreshed) return
521
505
 
522
- if(row.tab === self.active_tab) {
523
- self.theme.markTabActive(row);
524
- }
525
- else {
526
- self.theme.markTabInactive(row);
506
+ if (refreshHeaders) {
507
+ row.tab_text.textContent = row.getHeaderText()
508
+ } else {
509
+ /* All rows of simple properties point to the same tab, so refresh just once */
510
+ if (basicTabPresent && row.tab === this.rows[this.basicTab].tab) basicTabRefreshed = true
511
+
512
+ if (row.tab === this.active_tab) {
513
+ this.theme.markTabActive(row)
514
+ } else {
515
+ this.theme.markTabInactive(row)
527
516
  }
528
517
  }
529
- });
530
- },
531
- build: function() {
532
- var self = this;
533
-
534
- var isCategoriesFormat = (this.format === 'categories');
535
- this.rows=[];
536
- this.active_tab = null;
537
-
538
- // If the object should be rendered as a table row
539
- if(this.options.table_row) {
540
- this.editor_holder = this.container;
541
- $each(this.editors, function(key,editor) {
542
- var holder = self.theme.getTableCell();
543
- self.editor_holder.appendChild(holder);
544
-
545
- editor.setContainer(holder);
546
- editor.build();
547
- editor.postBuild();
548
- editor.setOptInCheckbox(editor.header);
549
-
550
- if(self.editors[key].options.hidden) {
551
- holder.style.display = 'none';
518
+ })
519
+ }
520
+
521
+ build () {
522
+ const isCategoriesFormat = (this.format === 'categories')
523
+ this.rows = []
524
+ this.active_tab = null
525
+
526
+ /* If the object should be rendered as a table row */
527
+ if (this.options.table_row) {
528
+ this.editor_holder = this.container
529
+ Object.entries(this.editors).forEach(([key, editor]) => {
530
+ const holder = this.theme.getTableCell()
531
+ this.editor_holder.appendChild(holder)
532
+
533
+ editor.setContainer(holder)
534
+ editor.build()
535
+ editor.postBuild()
536
+ editor.setOptInCheckbox(editor.header)
537
+
538
+ editor.setValue(editor.getDefault(), true)
539
+
540
+ if (this.editors[key].options.hidden) {
541
+ holder.style.display = 'none'
552
542
  }
553
- if(self.editors[key].options.input_width) {
554
- holder.style.width = self.editors[key].options.input_width;
543
+ if (this.editors[key].options.input_width) {
544
+ holder.style.width = this.editors[key].options.input_width
555
545
  }
556
- });
557
- }
558
- // If the object should be rendered as a table
559
- else if(this.options.table) {
560
- // TODO: table display format
561
- throw "Not supported yet";
562
- }
563
- // If the object should be rendered as a div
564
- else {
565
- this.header = document.createElement('label');
566
- this.header.textContent = this.getTitle();
567
- this.title = this.theme.getHeader(this.header);
568
- this.container.appendChild(this.title);
569
- this.container.style.position = 'relative';
570
-
571
- // Edit JSON modal
572
- this.editjson_holder = this.theme.getModal();
573
- this.editjson_textarea = this.theme.getTextareaInput();
574
- this.editjson_textarea.style.height = '170px';
575
- this.editjson_textarea.style.width = '300px';
576
- this.editjson_textarea.style.display = 'block';
577
- this.editjson_save = this.getButton('Save','save','Save');
578
- this.editjson_save.classList.add('json-editor-btntype-save');
579
- this.editjson_save.addEventListener('click',function(e) {
580
- e.preventDefault();
581
- e.stopPropagation();
582
- self.saveJSON();
583
- });
584
- this.editjson_copy = this.getButton('Copy','copy','Copy');
585
- this.editjson_copy.classList.add('json-editor-btntype-copy');
586
- this.editjson_copy.addEventListener('click',function(e) {
587
- e.preventDefault();
588
- e.stopPropagation();
589
- self.copyJSON();
590
- });
591
- this.editjson_cancel = this.getButton('Cancel','cancel','Cancel');
592
- this.editjson_cancel.classList.add('json-editor-btntype-cancel');
593
- this.editjson_cancel.addEventListener('click',function(e) {
594
- e.preventDefault();
595
- e.stopPropagation();
596
- self.hideEditJSON();
597
- });
598
- this.editjson_holder.appendChild(this.editjson_textarea);
599
- this.editjson_holder.appendChild(this.editjson_save);
600
- this.editjson_holder.appendChild(this.editjson_copy);
601
- this.editjson_holder.appendChild(this.editjson_cancel);
602
-
603
- // Manage Properties modal
604
- this.addproperty_holder = this.theme.getModal();
605
- this.addproperty_list = document.createElement('div');
606
- this.addproperty_list.style.width = '295px';
607
- this.addproperty_list.style.maxHeight = '160px';
608
- this.addproperty_list.style.padding = '5px 0';
609
- this.addproperty_list.style.overflowY = 'auto';
610
- this.addproperty_list.style.overflowX = 'hidden';
611
- this.addproperty_list.style.paddingLeft = '5px';
612
- this.addproperty_list.setAttribute('class', 'property-selector');
613
- this.addproperty_add = this.getButton('add','add','add');
614
- this.addproperty_add.classList.add('json-editor-btntype-add');
615
- this.addproperty_input = this.theme.getFormInputField('text');
616
- this.addproperty_input.setAttribute('placeholder','Property name...');
617
- this.addproperty_input.style.width = '220px';
618
- this.addproperty_input.style.marginBottom = '0';
619
- this.addproperty_input.style.display = 'inline-block';
620
- this.addproperty_add.addEventListener('click',function(e) {
621
- e.preventDefault();
622
- e.stopPropagation();
623
- if(self.addproperty_input.value) {
624
- if(self.editors[self.addproperty_input.value]) {
625
- window.alert('there is already a property with that name');
626
- return;
546
+ })
547
+ /* If the object should be rendered as a table */
548
+ } else if (this.options.table) {
549
+ /* TODO: table display format */
550
+ throw new Error('Not supported yet')
551
+ /* If the object should be rendered as a div */
552
+ } else {
553
+ this.header = ''
554
+ if (!this.options.compact) {
555
+ this.header = document.createElement('span')
556
+ this.header.textContent = this.getTitle()
557
+ }
558
+ this.title = this.theme.getHeader(this.header, this.getPathDepth())
559
+ this.title.classList.add('je-object__title')
560
+ this.controls = this.theme.getButtonHolder()
561
+ this.controls.classList.add('je-object__controls')
562
+
563
+ this.container.appendChild(this.title)
564
+ this.container.appendChild(this.controls)
565
+ this.container.classList.add('je-object__container')
566
+
567
+ /* Edit JSON modal */
568
+ this.editjson_holder = this.theme.getModal()
569
+ this.editjson_textarea_label = this.theme.getHiddenLabel(this.translate('button_edit_json'))
570
+ this.editjson_textarea_label.setAttribute('for', this.path + '-' + 'edit-json-textarea')
571
+ this.editjson_textarea = this.theme.getTextareaInput()
572
+ this.editjson_textarea.setAttribute('id', this.path + '-' + 'edit-json-textarea')
573
+ this.editjson_textarea.setAttribute('aria-labelledby', this.path + '-' + 'edit-json-textarea')
574
+ this.editjson_textarea.classList.add('je-edit-json--textarea')
575
+ this.editjson_save = this.getButton('button_save', 'save', 'button_save')
576
+ this.editjson_save.classList.add('json-editor-btntype-save')
577
+ this.editjson_save.addEventListener('click', (e) => {
578
+ e.preventDefault()
579
+ e.stopPropagation()
580
+ this.saveJSON()
581
+ })
582
+ this.editjson_copy = this.getButton('button_copy', 'copy', 'button_copy')
583
+ this.editjson_copy.classList.add('json-editor-btntype-copy')
584
+ this.editjson_copy.addEventListener('click', (e) => {
585
+ e.preventDefault()
586
+ e.stopPropagation()
587
+ this.copyJSON()
588
+ })
589
+ this.editjson_cancel = this.getButton('button_cancel', 'cancel', 'button_cancel')
590
+ this.editjson_cancel.classList.add('json-editor-btntype-cancel')
591
+ this.editjson_cancel.addEventListener('click', (e) => {
592
+ e.preventDefault()
593
+ e.stopPropagation()
594
+ this.hideEditJSON()
595
+ })
596
+ this.editjson_holder.appendChild(this.editjson_textarea_label)
597
+ this.editjson_holder.appendChild(this.editjson_textarea)
598
+ this.editjson_holder.appendChild(this.editjson_save)
599
+ this.editjson_holder.appendChild(this.editjson_copy)
600
+ this.editjson_holder.appendChild(this.editjson_cancel)
601
+
602
+ /* Manage Properties modal */
603
+ this.addproperty_holder = this.theme.getModal()
604
+ this.addproperty_list = document.createElement('div')
605
+ this.addproperty_list.classList.add('property-selector')
606
+ this.addproperty_add = this.getButton('button_add', 'add', 'button_add')
607
+ this.addproperty_add.classList.add('json-editor-btntype-add')
608
+
609
+ this.addproperty_input = this.theme.getFormInputField('text')
610
+ this.addproperty_input.setAttribute('placeholder', 'Property name...')
611
+
612
+ this.addproperty_input_label = this.theme.getHiddenLabel(this.translate('button_properties'))
613
+ this.addproperty_input_label.setAttribute('for', this.path + '-' + 'property-selector')
614
+
615
+ this.addproperty_input.classList.add('property-selector-input')
616
+ this.addproperty_input.setAttribute('id', this.path + '-' + 'property-selector')
617
+ this.addproperty_input.setAttribute('aria-labelledby', this.path + '-' + 'property-selector')
618
+
619
+ this.addproperty_add.addEventListener('click', (e) => {
620
+ e.preventDefault()
621
+ e.stopPropagation()
622
+ if (this.addproperty_input.value) {
623
+ if (this.editors[this.addproperty_input.value]) {
624
+ window.alert('there is already a property with that name')
625
+ return
627
626
  }
628
627
 
629
- self.addObjectProperty(self.addproperty_input.value);
630
- if(self.editors[self.addproperty_input.value]) {
631
- self.editors[self.addproperty_input.value].disable();
628
+ this.addObjectProperty(this.addproperty_input.value)
629
+ if (this.editors[this.addproperty_input.value]) {
630
+ this.editors[this.addproperty_input.value].disable()
632
631
  }
633
- self.onChange(true);
632
+ const key = this.editors[this.addproperty_input.value].key
633
+ const type = this.editors[this.addproperty_input.value].type
634
+ const path = this.editors[this.addproperty_input.value].path
635
+
636
+ this.onChange(true, false, {
637
+ event: 'add',
638
+ data: { key, type, path }
639
+ })
634
640
  }
635
- });
636
- this.addproperty_holder.appendChild(this.addproperty_list);
637
- this.addproperty_holder.appendChild(this.addproperty_input);
638
- this.addproperty_holder.appendChild(this.addproperty_add);
639
- var spacer = document.createElement('div');
640
- spacer.style.clear = 'both';
641
- this.addproperty_holder.appendChild(spacer);
642
-
643
- // Close properties modal if clicked outside modal
644
- document.addEventListener('click', function(e) {
645
- if (!this.addproperty_holder.contains(e.target) && this.adding_property) {
646
- e.preventDefault();
647
- e.stopPropagation();
648
- this.toggleAddProperty();
649
- }
650
- }.bind(this));
641
+ })
642
+ this.addproperty_input.addEventListener('input', (e) => {
643
+ e.target.previousSibling.previousSibling.childNodes.forEach((value) => {
644
+ let searchTerm = value.innerText
645
+ let propertyTitle = e.target.value
651
646
 
652
- // Description
653
- if(this.schema.description) {
654
- this.description = this.theme.getDescription(this.schema.description);
655
- this.container.appendChild(this.description);
656
- }
647
+ const caseSensitivePropertySearch = this.options.case_sensitive_property_search || this.jsoneditor.options.case_sensitive_property_search
657
648
 
658
- // Validation error placeholder area
659
- this.error_holder = document.createElement('div');
660
- this.container.appendChild(this.error_holder);
661
-
662
- // Container for child editor area
663
- this.editor_holder = this.theme.getIndentedPanel();
664
- this.container.appendChild(this.editor_holder);
665
-
666
- // Container for rows of child editors
667
- this.row_container = this.theme.getGridContainer();
649
+ if (!caseSensitivePropertySearch) {
650
+ searchTerm = searchTerm.toLowerCase()
651
+ propertyTitle = propertyTitle.toLowerCase()
652
+ }
668
653
 
669
- if(isCategoriesFormat) {
670
- this.tabs_holder = this.theme.getTopTabHolder(this.getValidId(this.schema.title));
671
- this.tabPanesContainer = this.theme.getTopTabContentHolder(this.tabs_holder);
672
- this.editor_holder.appendChild(this.tabs_holder);
654
+ if (searchTerm.includes(propertyTitle)) {
655
+ value.style.display = ''
656
+ } else {
657
+ value.style.display = 'none'
658
+ }
659
+ })
660
+ })
661
+ this.addproperty_holder.appendChild(this.addproperty_list)
662
+ this.addproperty_holder.appendChild(this.addproperty_input_label)
663
+ this.addproperty_holder.appendChild(this.addproperty_input)
664
+ this.addproperty_holder.appendChild(this.addproperty_add)
665
+ const spacer = document.createElement('div')
666
+ spacer.style.clear = 'both'
667
+ this.addproperty_holder.appendChild(spacer)
668
+
669
+ /* Close properties modal if clicked outside modal */
670
+ this.onOutsideModalClickListener = this.onOutsideModalClick.bind(this)
671
+ document.addEventListener('click', this.onOutsideModalClickListener, true)
672
+
673
+ /* Description */
674
+ if (this.schema.description) {
675
+ this.description = this.theme.getDescription(this.translateProperty(this.schema.description))
676
+ this.container.appendChild(this.description)
673
677
  }
674
- else {
675
- this.tabs_holder = this.theme.getTabHolder(this.getValidId(this.schema.title));
676
- this.tabPanesContainer = this.theme.getTabContentHolder(this.tabs_holder);
677
- this.editor_holder.appendChild(this.row_container);
678
+
679
+ /* Validation error placeholder area */
680
+ this.error_holder = document.createElement('div')
681
+ this.container.appendChild(this.error_holder)
682
+
683
+ /* Container for child editor area */
684
+ this.editor_holder = this.theme.getIndentedPanel()
685
+ this.container.appendChild(this.editor_holder)
686
+
687
+ /* Container for rows of child editors */
688
+ this.row_container = this.theme.getGridContainer()
689
+
690
+ if (isCategoriesFormat) {
691
+ this.tabs_holder = this.theme.getTopTabHolder(this.getValidId(this.translateProperty(this.schema.title)))
692
+ this.tabPanesContainer = this.theme.getTopTabContentHolder(this.tabs_holder)
693
+ this.editor_holder.appendChild(this.tabs_holder)
694
+ } else {
695
+ this.tabs_holder = this.theme.getTabHolder(this.getValidId(this.translateProperty(this.schema.title)))
696
+ this.tabPanesContainer = this.theme.getTabContentHolder(this.tabs_holder)
697
+ this.editor_holder.appendChild(this.row_container)
678
698
  }
679
699
 
680
- $each(this.editors, function(key,editor) {
681
- var aPane = self.theme.getTabContent();
682
- var holder = self.theme.getGridColumn();
683
- var isObjOrArray = (editor.schema && (editor.schema.type === 'object' || editor.schema.type === 'array')) ? true : false;
684
- aPane.isObjOrArray = isObjOrArray;
685
-
686
- if(isCategoriesFormat){
687
- if(isObjOrArray) {
688
- var single_row_container = self.theme.getGridContainer();
689
- single_row_container.appendChild(holder);
690
- aPane.appendChild(single_row_container);
691
- self.tabPanesContainer.appendChild(aPane);
692
- self.row_container = single_row_container;
693
- }
694
- else {
695
- if(typeof self.row_container_basic === 'undefined'){
696
- self.row_container_basic = self.theme.getGridContainer();
697
- aPane.appendChild(self.row_container_basic);
698
- if(self.tabPanesContainer.childElementCount == 0){
699
- self.tabPanesContainer.appendChild(aPane);
700
- }
701
- else {
702
- self.tabPanesContainer.insertBefore(aPane,self.tabPanesContainer.childNodes[1]);
700
+ Object.values(this.editors).forEach(editor => {
701
+ const aPane = this.theme.getTabContent()
702
+ const holder = this.theme.getGridColumn()
703
+ const isObjOrArray = !!((editor.schema && (editor.schema.type === 'object' || editor.schema.type === 'array')))
704
+ aPane.isObjOrArray = isObjOrArray
705
+
706
+ if (isCategoriesFormat) {
707
+ if (isObjOrArray) {
708
+ const singleRowContainer = this.theme.getGridContainer()
709
+ singleRowContainer.appendChild(holder)
710
+ aPane.appendChild(singleRowContainer)
711
+ this.tabPanesContainer.appendChild(aPane)
712
+ this.row_container = singleRowContainer
713
+ } else {
714
+ if (typeof this.row_container_basic === 'undefined') {
715
+ this.row_container_basic = this.theme.getGridContainer()
716
+ aPane.appendChild(this.row_container_basic)
717
+ if (this.tabPanesContainer.childElementCount === 0) {
718
+ this.tabPanesContainer.appendChild(aPane)
719
+ } else {
720
+ this.tabPanesContainer.insertBefore(aPane, this.tabPanesContainer.childNodes[1])
703
721
  }
704
722
  }
705
- self.row_container_basic.appendChild(holder);
723
+ this.row_container_basic.appendChild(holder)
706
724
  }
707
725
 
708
- self.addRow(editor,self.tabs_holder,aPane);
709
-
710
- aPane.id = self.getValidId(editor.schema.title); //editor.schema.path//tab_text.textContent
726
+ this.addRow(editor, this.tabs_holder, aPane)
711
727
 
712
- }
713
- else {
714
- self.row_container.appendChild(holder);
728
+ aPane.id = this.getValidId(editor.schema.title) /* editor.schema.path//tab_text.textContent */
729
+ } else {
730
+ this.row_container.appendChild(holder)
715
731
  }
716
732
 
717
- editor.setContainer(holder);
718
- editor.build();
719
- editor.postBuild();
720
- editor.setOptInCheckbox(editor.header);
721
- });
733
+ editor.setContainer(holder)
734
+ editor.build()
735
+ editor.postBuild()
736
+ editor.setOptInCheckbox(editor.header)
737
+ })
722
738
 
723
- if(this.rows[0]){
724
- $trigger(this.rows[0].tab,'click');
739
+ if (this.rows[0]) {
740
+ trigger(this.rows[0].tab, 'click')
725
741
  }
726
742
 
727
- // Control buttons
728
- this.title_controls = this.theme.getHeaderButtonHolder();
729
- this.editjson_controls = this.theme.getHeaderButtonHolder();
730
- this.addproperty_controls = this.theme.getHeaderButtonHolder();
731
- this.title.appendChild(this.title_controls);
732
- this.title.appendChild(this.editjson_controls);
733
- this.title.appendChild(this.addproperty_controls);
734
-
735
- // Show/Hide button
736
- this.collapsed = false;
737
- this.toggle_button = this.getButton('', 'collapse', this.translate('button_collapse'));
738
- this.toggle_button.classList.add('json-editor-btntype-toggle');
739
- this.title_controls.appendChild(this.toggle_button);
740
- this.toggle_button.addEventListener('click',function(e) {
741
- e.preventDefault();
742
- e.stopPropagation();
743
- if(self.collapsed) {
744
- self.editor_holder.style.display = '';
745
- self.collapsed = false;
746
- self.setButtonText(self.toggle_button,'','collapse',self.translate('button_collapse'));
747
- }
748
- else {
749
- self.editor_holder.style.display = 'none';
750
- self.collapsed = true;
751
- self.setButtonText(self.toggle_button,'','expand',self.translate('button_expand'));
743
+ /* Show/Hide button */
744
+ this.collapsed = false
745
+ this.collapse_control = this.getButton('', 'collapse', 'button_collapse')
746
+ this.collapse_control.classList.add('json-editor-btntype-toggle')
747
+ this.title.insertBefore(this.collapse_control, this.title.childNodes[0])
748
+
749
+ this.collapse_control.addEventListener('click', (e) => {
750
+ e.preventDefault()
751
+ e.stopPropagation()
752
+ if (this.collapsed) {
753
+ this.editor_holder.style.display = ''
754
+ this.collapsed = false
755
+ this.setButtonText(this.collapse_control, '', 'collapse', 'button_collapse')
756
+ } else {
757
+ this.editor_holder.style.display = 'none'
758
+ this.collapsed = true
759
+ this.setButtonText(this.collapse_control, '', 'expand', 'button_expand')
752
760
  }
753
- });
761
+ })
754
762
 
755
- // If it should start collapsed
756
- if(this.options.collapsed) {
757
- $trigger(this.toggle_button,'click');
763
+ /* If it should start collapsed */
764
+ if (this.options.collapsed) {
765
+ trigger(this.collapse_control, 'click')
758
766
  }
759
767
 
760
- // Collapse button disabled
761
- if(this.schema.options && typeof this.schema.options.disable_collapse !== "undefined") {
762
- if(this.schema.options.disable_collapse) this.toggle_button.style.display = 'none';
763
- }
764
- else if(this.jsoneditor.options.disable_collapse) {
765
- this.toggle_button.style.display = 'none';
768
+ /* Collapse button disabled */
769
+ if (this.schema.options && typeof this.schema.options.disable_collapse !== 'undefined') {
770
+ if (this.schema.options.disable_collapse) this.collapse_control.style.display = 'none'
771
+ } else if (this.jsoneditor.options.disable_collapse) {
772
+ this.collapse_control.style.display = 'none'
766
773
  }
767
774
 
768
- // Edit JSON Button
769
- this.editjson_button = this.getButton('JSON','edit','Edit JSON');
770
- this.editjson_button.classList.add('json-editor-btntype-editjson');
771
- this.editjson_button.addEventListener('click',function(e) {
772
- e.preventDefault();
773
- e.stopPropagation();
774
- self.toggleEditJSON();
775
- });
776
- this.editjson_controls.appendChild(this.editjson_button);
777
- this.editjson_controls.appendChild(this.editjson_holder);
778
-
779
- // Edit JSON Buttton disabled
780
- if(this.schema.options && typeof this.schema.options.disable_edit_json !== "undefined") {
781
- if(this.schema.options.disable_edit_json) this.editjson_button.style.display = 'none';
782
- }
783
- else if(this.jsoneditor.options.disable_edit_json) {
784
- this.editjson_button.style.display = 'none';
775
+ /* Edit JSON Button */
776
+ this.editjson_control = this.getButton('JSON', 'edit', 'button_edit_json')
777
+ this.editjson_control.classList.add('json-editor-btntype-editjson')
778
+ this.editjson_control.addEventListener('click', (e) => {
779
+ e.preventDefault()
780
+ e.stopPropagation()
781
+ this.toggleEditJSON()
782
+ })
783
+ this.controls.appendChild(this.editjson_control)
784
+ this.controls.insertBefore(this.editjson_holder, this.controls.childNodes[0])
785
+
786
+ /* Edit JSON Buttton disabled */
787
+ if (this.schema.options && typeof this.schema.options.disable_edit_json !== 'undefined') {
788
+ if (this.schema.options.disable_edit_json) this.editjson_control.style.display = 'none'
789
+ } else if (this.jsoneditor.options.disable_edit_json) {
790
+ this.editjson_control.style.display = 'none'
785
791
  }
786
792
 
787
- // Object Properties Button
788
- this.addproperty_button = this.getButton('Properties','edit', self.translate('button_object_properties'));
789
- this.addproperty_button.classList.add('json-editor-btntype-properties');
790
- this.addproperty_button.addEventListener('click',function(e) {
791
- e.preventDefault();
792
- e.stopPropagation();
793
- self.toggleAddProperty();
794
- });
795
- this.addproperty_controls.appendChild(this.addproperty_button);
796
- this.addproperty_controls.appendChild(this.addproperty_holder);
797
- this.refreshAddProperties();
798
-
799
- // non required properties start deactivated
800
- this.deactivateNonRequiredProperties();
801
-
793
+ /* Object Properties Button */
794
+ this.addproperty_button = this.getButton('properties', 'edit_properties', 'button_object_properties')
795
+ this.addproperty_button.classList.add('json-editor-btntype-properties')
796
+ this.addproperty_button.addEventListener('click', (e) => {
797
+ e.preventDefault()
798
+ e.stopPropagation()
799
+ this.toggleAddProperty()
800
+ })
801
+ this.controls.appendChild(this.addproperty_button)
802
+ this.controls.insertBefore(this.addproperty_holder, this.controls.childNodes[1])
803
+
804
+ this.refreshAddProperties()
805
+
806
+ /* non required properties start deactivated */
807
+ this.deactivateNonRequiredProperties(false)
802
808
  }
803
809
 
804
- // Fix table cell ordering
805
- if(this.options.table_row) {
806
- this.editor_holder = this.container;
807
- $each(this.property_order,function(i,key) {
808
- self.editor_holder.appendChild(self.editors[key].container);
809
- });
810
+ /* Fix table cell ordering */
811
+ if (this.options.table_row) {
812
+ this.editor_holder = this.container
813
+ this.property_order.forEach(key => {
814
+ this.editor_holder.appendChild(this.editors[key].container)
815
+ })
816
+ /* Layout object editors in grid if needed */
817
+ } else {
818
+ /* Initial layout */
819
+ this.layoutEditors()
820
+ /* Do it again now that we know the approximate heights of elements */
821
+ this.layoutEditors()
810
822
  }
811
- // Layout object editors in grid if needed
812
- else {
813
- // Initial layout
814
- this.layoutEditors();
815
- // Do it again now that we know the approximate heights of elements
816
- this.layoutEditors();
823
+
824
+ if (this.schema.readOnly || this.schema.readonly) {
825
+ this.disable()
817
826
  }
818
- },
819
- deactivateNonRequiredProperties: function () {
820
- var self = this;
821
- // the show_opt_in editor option is for backward compatibility
822
- if (this.jsoneditor.options.show_opt_in || this.options.show_opt_in) {
823
- $each(this.editors, function(key, editor) {
824
- if (!self.isRequired(editor)) {
825
- self.editors[key].deactivate();
827
+ }
828
+
829
+ deactivateNonRequiredProperties (recursive) {
830
+ /* the show_opt_in editor option is for backward compatibility */
831
+ const globalOptIn = this.jsoneditor.options.show_opt_in
832
+ const editorOptInDefined = (typeof this.options.show_opt_in !== 'undefined')
833
+ const editorOptInEnabled = (editorOptInDefined && this.options.show_opt_in === true)
834
+ const editorOptInDisabled = (editorOptInDefined && this.options.show_opt_in === false)
835
+ if (editorOptInEnabled || (!editorOptInDisabled && globalOptIn) || (!editorOptInDefined && globalOptIn)) {
836
+ Object.entries(this.editors).forEach(([key, editor]) => {
837
+ if (!this.isRequiredObject(editor)) {
838
+ this.editors[key].deactivate()
839
+ }
840
+ if (recursive && typeof this.editors[key].deactivateNonRequiredProperties === 'function') {
841
+ this.editors[key].deactivateNonRequiredProperties(recursive)
826
842
  }
827
- });
843
+ })
828
844
  }
829
- },
830
- showEditJSON: function() {
831
- if(!this.editjson_holder) return;
832
- this.hideAddProperty();
833
-
834
- // Position the form directly beneath the button
835
- // TODO: edge detection
836
- this.editjson_holder.style.left = this.editjson_button.offsetLeft+"px";
837
- this.editjson_holder.style.top = this.editjson_button.offsetTop + this.editjson_button.offsetHeight+"px";
838
-
839
- // Start the textarea with the current value
840
- this.editjson_textarea.value = JSON.stringify(this.getValue(),null,2);
841
-
842
- // Disable the rest of the form while editing JSON
843
- this.disable();
844
-
845
- this.editjson_holder.style.display = '';
846
- this.editjson_button.disabled = false;
847
- this.editing_json = true;
848
- },
849
- hideEditJSON: function() {
850
- if(!this.editjson_holder) return;
851
- if(!this.editing_json) return;
852
-
853
- this.editjson_holder.style.display = 'none';
854
- this.enable();
855
- this.editing_json = false;
856
- },
857
- copyJSON: function() {
858
- if(!this.editjson_holder) return;
859
- var ta = document.createElement('textarea');
860
- ta.value = this.editjson_textarea.value;
861
- ta.setAttribute('readonly', '');
862
- ta.style.position = 'absolute';
863
- ta.style.left = '-9999px';
864
- document.body.appendChild(ta);
865
- ta.select();
866
- document.execCommand('copy');
867
- document.body.removeChild(ta);
868
- },
869
- saveJSON: function() {
870
- if(!this.editjson_holder) return;
845
+ }
846
+
847
+ showEditJSON () {
848
+ if (!this.editjson_holder) return
849
+ this.hideAddProperty()
850
+
851
+ /* Position the form directly beneath the button */
852
+ /* TODO: edge detection */
853
+ this.editjson_holder.style.left = `${this.editjson_control.offsetLeft}px`
854
+ this.editjson_holder.style.top = `${this.editjson_control.offsetTop + this.editjson_control.offsetHeight}px`
855
+
856
+ /* Start the textarea with the current value */
857
+ this.editjson_textarea.value = JSON.stringify(this.getValue(), null, 2)
858
+
859
+ /* Disable the rest of the form while editing JSON */
860
+ this.disable()
861
+
862
+ this.editjson_holder.style.display = ''
863
+ this.editjson_control.disabled = false
864
+ this.editing_json = true
865
+ }
866
+
867
+ hideEditJSON () {
868
+ if (!this.editjson_holder) return
869
+ if (!this.editing_json) return
870
+
871
+ this.editjson_holder.style.display = 'none'
872
+ this.enable()
873
+ this.editing_json = false
874
+ }
875
+
876
+ copyJSON () {
877
+ if (!this.editjson_holder) return
878
+ navigator.clipboard.writeText(this.editjson_textarea.value)
879
+ .catch((e) => window.alert(e))
880
+ }
881
+
882
+ saveJSON () {
883
+ if (!this.editjson_holder) return
871
884
 
872
885
  try {
873
- var json = JSON.parse(this.editjson_textarea.value);
874
- this.setValue(json);
875
- this.hideEditJSON();
876
- this.onChange(true);
886
+ const json = JSON.parse(this.editjson_textarea.value)
887
+ this.setValue(json)
888
+ this.hideEditJSON()
889
+ this.onChange(true)
890
+ } catch (e) {
891
+ window.alert('invalid JSON')
892
+ throw e
877
893
  }
878
- catch(e) {
879
- window.alert('invalid JSON');
880
- throw e;
881
- }
882
- },
883
- toggleEditJSON: function() {
884
- if(this.editing_json) this.hideEditJSON();
885
- else this.showEditJSON();
886
- },
887
- insertPropertyControlUsingPropertyOrder: function (property, control, container) {
888
- var propertyOrder;
889
- if (this.schema.properties[property])
890
- propertyOrder = this.schema.properties[property].propertyOrder;
891
- if (typeof propertyOrder !== "number") propertyOrder = 1000;
892
- control.propertyOrder = propertyOrder;
893
-
894
- for (var i = 0; i < container.childNodes.length; i++) {
895
- var child = container.childNodes[i];
894
+ }
895
+
896
+ toggleEditJSON () {
897
+ if (this.editing_json) this.hideEditJSON()
898
+ else this.showEditJSON()
899
+ }
900
+
901
+ insertPropertyControlUsingPropertyOrder (property, control, container) {
902
+ let propertyOrder
903
+ if (this.schema.properties[property]) { propertyOrder = this.schema.properties[property].propertyOrder }
904
+ if (typeof propertyOrder !== 'number') propertyOrder = 1000
905
+ control.propertyOrder = propertyOrder
906
+
907
+ for (let i = 0; i < container.childNodes.length; i++) {
908
+ const child = container.childNodes[i]
896
909
  if (control.propertyOrder < child.propertyOrder) {
897
- this.addproperty_list.insertBefore(control, child);
898
- control = null;
899
- break;
910
+ this.addproperty_list.insertBefore(control, child)
911
+ control = null
912
+ break
900
913
  }
901
914
  }
902
915
  if (control) {
903
- this.addproperty_list.appendChild(control);
916
+ this.addproperty_list.appendChild(control)
904
917
  }
905
- },
906
- addPropertyCheckbox: function(key) {
907
- var self = this;
908
- var checkbox, label, labelText, control;
918
+ }
909
919
 
910
- checkbox = self.theme.getCheckbox();
911
- checkbox.style.width = 'auto';
920
+ addPropertyCheckbox (key) {
921
+ let labelText
912
922
 
913
- if (this.schema.properties[key] && this.schema.properties[key].title)
914
- labelText = this.schema.properties[key].title;
915
- else
916
- labelText = key;
923
+ const checkbox = this.theme.getCheckbox()
917
924
 
918
- label = self.theme.getCheckboxLabel(labelText);
925
+ if (this.schema.properties[key] && this.schema.properties[key].title) { labelText = this.schema.properties[key].title } else { labelText = key }
919
926
 
920
- control = self.theme.getFormControl(label,checkbox);
921
- control.style.paddingBottom = control.style.marginBottom = control.style.paddingTop = control.style.marginTop = 0;
922
- control.style.height = 'auto';
923
- //control.style.overflowY = 'hidden';
927
+ const label = this.theme.getCheckboxLabel(labelText)
924
928
 
925
- this.insertPropertyControlUsingPropertyOrder(key, control, this.addproperty_list);
929
+ const control = this.theme.getFormControl(label, checkbox, null, null, this.path + '-' + key)
930
+ control.style.paddingBottom = control.style.marginBottom = control.style.paddingTop = control.style.marginTop = 0
931
+ control.style.height = 'auto'
932
+ /* control.style.overflowY = 'hidden'; */
926
933
 
927
- checkbox.checked = key in this.editors;
928
- checkbox.addEventListener('change',function() {
929
- if(checkbox.checked) {
930
- self.addObjectProperty(key);
934
+ this.insertPropertyControlUsingPropertyOrder(key, control, this.addproperty_list)
935
+
936
+ checkbox.checked = key in this.editors
937
+ checkbox.addEventListener('change', () => {
938
+ if (checkbox.checked) {
939
+ this.addObjectProperty(key)
940
+ } else {
941
+ this.removeObjectProperty(key)
931
942
  }
932
- else {
933
- self.removeObjectProperty(key);
943
+ this.onChange(true)
944
+ })
945
+ this.addproperty_checkboxes[key] = checkbox
946
+
947
+ return checkbox
948
+ }
949
+
950
+ showAddProperty () {
951
+ if (!this.addproperty_holder) return
952
+ this.hideEditJSON()
953
+
954
+ /* Position the form directly beneath the button */
955
+ /* TODO: edge detection */
956
+ this.addproperty_holder.style.left = `${this.addproperty_button.offsetLeft}px`
957
+ this.addproperty_holder.style.top = `${this.addproperty_button.offsetTop + this.addproperty_button.offsetHeight}px`
958
+
959
+ /* Disable the rest of the form while editing JSON */
960
+ this.disable()
961
+
962
+ this.adding_property = true
963
+ this.addproperty_button.disabled = false
964
+ this.addproperty_holder.style.display = ''
965
+ this.refreshAddProperties()
966
+ }
967
+
968
+ hideAddProperty () {
969
+ if (!this.addproperty_holder) return
970
+ if (!this.adding_property) return
971
+
972
+ this.addproperty_holder.style.display = 'none'
973
+ this.enable()
974
+
975
+ this.adding_property = false
976
+ }
977
+
978
+ toggleAddProperty () {
979
+ if (this.adding_property) this.hideAddProperty()
980
+ else this.showAddProperty()
981
+ }
982
+
983
+ removeObjectProperty (property) {
984
+ if (this.editors[property]) {
985
+ // do not destroy dependent editors
986
+ if (this.editors[property].schema?.options?.dependencies) {
987
+ return
934
988
  }
935
- self.onChange(true);
936
- });
937
- self.addproperty_checkboxes[key] = checkbox;
938
-
939
- return checkbox;
940
- },
941
- showAddProperty: function() {
942
- if(!this.addproperty_holder) return;
943
- this.hideEditJSON();
944
-
945
- // Position the form directly beneath the button
946
- // TODO: edge detection
947
- this.addproperty_holder.style.left = this.addproperty_button.offsetLeft+"px";
948
- this.addproperty_holder.style.top = this.addproperty_button.offsetTop + this.addproperty_button.offsetHeight+"px";
949
-
950
- // Disable the rest of the form while editing JSON
951
- this.disable();
952
-
953
- this.adding_property = true;
954
- this.addproperty_button.disabled = false;
955
- this.addproperty_holder.style.display = '';
956
- this.refreshAddProperties();
957
- },
958
- hideAddProperty: function() {
959
- if(!this.addproperty_holder) return;
960
- if(!this.adding_property) return;
961
-
962
- this.addproperty_holder.style.display = 'none';
963
- this.enable();
964
-
965
- this.adding_property = false;
966
- },
967
- toggleAddProperty: function() {
968
- if(this.adding_property) this.hideAddProperty();
969
- else this.showAddProperty();
970
- },
971
- removeObjectProperty: function(property) {
972
- if(this.editors[property]) {
973
- this.editors[property].unregister();
974
- delete this.editors[property];
975
-
976
- this.refreshValue();
977
- this.layoutEditors();
978
- }
979
- },
980
- addObjectProperty: function(name, prebuild_only) {
981
- var self = this;
982
-
983
- // Property is already added
984
- if(this.editors[name]) return;
985
-
986
- // Property was added before and is cached
987
- if(this.cached_editors[name]) {
988
- this.editors[name] = this.cached_editors[name];
989
- if(prebuild_only) return;
990
- this.editors[name].register();
989
+
990
+ this.editors[property].unregister()
991
+ delete this.editors[property]
992
+
993
+ this.refreshValue()
994
+ this.layoutEditors()
991
995
  }
992
- // New property
993
- else {
994
- if(!this.canHaveAdditionalProperties() && (!this.schema.properties || !this.schema.properties[name])) {
995
- return;
996
+ }
997
+
998
+ getSchemaOnMaxDepth (schema) {
999
+ return Object.keys(schema).reduce((acc, key) => {
1000
+ switch (key) {
1001
+ case '$ref':
1002
+ return acc
1003
+ case 'properties':
1004
+ case 'items':
1005
+ return {
1006
+ ...acc,
1007
+ [key]: {}
1008
+ }
1009
+ case 'additionalProperties':
1010
+ case 'propertyNames':
1011
+ return {
1012
+ ...acc,
1013
+ [key]: true
1014
+ }
1015
+ default:
1016
+ return {
1017
+ ...acc,
1018
+ [key]: schema[key]
1019
+ }
996
1020
  }
1021
+ }, {})
1022
+ }
997
1023
 
998
- var schema = self.getPropertySchema(name);
999
- if(typeof schema.propertyOrder !== 'number'){
1000
- // if the propertyOrder undefined, then set a smart default value.
1001
- schema.propertyOrder = Object.keys(self.editors).length + 1000;
1024
+ addObjectProperty (name, prebuildOnly) {
1025
+ /* Property is already added */
1026
+ if (this.editors[name]) return
1027
+
1028
+ /* Property was added before and is cached */
1029
+ if (this.cached_editors[name]) {
1030
+ this.editors[name] = this.cached_editors[name]
1031
+ if (prebuildOnly) return
1032
+ this.editors[name].register()
1033
+ /* New property */
1034
+ } else {
1035
+ if (!this.canHaveAdditionalProperties() && (!this.schema.properties || !this.schema.properties[name]) &&
1036
+ (!this.schema.patternProperties || !(Object.keys(this.schema.patternProperties).find(i => new RegExp(i).test(name))))) {
1037
+ return
1002
1038
  }
1003
1039
 
1040
+ const schema = this.getPropertySchema(name)
1041
+ if (typeof schema.propertyOrder !== 'number') {
1042
+ /* if the propertyOrder undefined, then set a smart default value. */
1043
+ schema.propertyOrder = Object.keys(this.editors).length + 1000
1044
+ }
1004
1045
 
1005
- // Add the property
1006
- var editor = self.jsoneditor.getEditorClass(schema);
1007
-
1008
- self.editors[name] = self.jsoneditor.createEditor(editor,{
1009
- jsoneditor: self.jsoneditor,
1010
- schema: schema,
1011
- path: self.path+'.'+name,
1012
- parent: self
1013
- });
1014
- self.editors[name].preBuild();
1015
-
1016
- if(!prebuild_only) {
1017
- var holder = self.theme.getChildEditorHolder();
1018
- self.editor_holder.appendChild(holder);
1019
- self.editors[name].setContainer(holder);
1020
- self.editors[name].build();
1021
- self.editors[name].postBuild();
1022
- self.editors[name].setOptInCheckbox(editor.header);
1023
- self.editors[name].activate();
1046
+ /* Add the property */
1047
+ const editor = this.jsoneditor.getEditorClass(schema)
1048
+
1049
+ const { max_depth: maxDepth } = this.jsoneditor.options
1050
+
1051
+ this.editors[name] = this.jsoneditor.createEditor(editor, {
1052
+ jsoneditor: this.jsoneditor,
1053
+ schema: !!maxDepth && this.currentDepth >= maxDepth ? this.getSchemaOnMaxDepth(schema) : schema,
1054
+ path: `${this.path}.${name}`,
1055
+ parent: this
1056
+ }, this.currentDepth + 1)
1057
+ this.editors[name].preBuild()
1058
+
1059
+ if (!prebuildOnly) {
1060
+ const holder = this.theme.getChildEditorHolder()
1061
+ this.editor_holder.appendChild(holder)
1062
+ this.editors[name].setContainer(holder)
1063
+ this.editors[name].build()
1064
+ this.editors[name].postBuild()
1065
+ this.editors[name].setOptInCheckbox(editor.header)
1066
+ this.editors[name].activate()
1024
1067
  }
1025
1068
 
1026
- self.cached_editors[name] = self.editors[name];
1069
+ this.cached_editors[name] = this.editors[name]
1027
1070
  }
1028
1071
 
1029
- // If we're only prebuilding the editors, don't refresh values
1030
- if(!prebuild_only) {
1031
- self.refreshValue();
1032
- self.layoutEditors();
1033
- }
1034
- },
1035
- onChildEditorChange: function(editor) {
1036
- this.refreshValue();
1037
- this._super(editor);
1038
- },
1039
- canHaveAdditionalProperties: function() {
1040
- if (typeof this.schema.additionalProperties === "boolean") {
1041
- return this.schema.additionalProperties;
1042
- }
1043
- return !this.jsoneditor.options.no_additional_properties;
1044
- },
1045
- destroy: function() {
1046
- $each(this.cached_editors, function(i,el) {
1047
- el.destroy();
1048
- });
1049
- if(this.editor_holder) this.editor_holder.innerHTML = '';
1050
- if(this.title && this.title.parentNode) this.title.parentNode.removeChild(this.title);
1051
- if(this.error_holder && this.error_holder.parentNode) this.error_holder.parentNode.removeChild(this.error_holder);
1052
-
1053
- this.editors = null;
1054
- this.cached_editors = null;
1055
- if(this.editor_holder && this.editor_holder.parentNode) this.editor_holder.parentNode.removeChild(this.editor_holder);
1056
- this.editor_holder = null;
1057
-
1058
- this._super();
1059
- },
1060
- getValue: function() {
1061
- if (!this.dependenciesFulfilled) {
1062
- return undefined;
1072
+ /* If we're only prebuilding the editors, don't refresh values */
1073
+ if (!prebuildOnly) {
1074
+ this.refreshValue()
1075
+ this.layoutEditors()
1063
1076
  }
1064
- var result = this._super();
1065
- if(this.jsoneditor.options.remove_empty_properties || this.options.remove_empty_properties) {
1066
- for (var i in result) {
1067
- if (result.hasOwnProperty(i)) {
1068
- if (typeof result[i] === 'undefined' || result[i] === '' || result[i] === Object(result[i]) && Object.keys(result[i]).length == 0 && result[i].constructor == Object) {
1069
- delete result[i];
1070
- }
1071
- }
1072
- }
1077
+ }
1078
+
1079
+ onOutsideModalClick (e) {
1080
+ const path = e.path || (e.composedPath && e.composedPath())
1081
+ if (this.addproperty_holder && !this.addproperty_holder.contains(path[0]) && this.adding_property) {
1082
+ e.preventDefault()
1083
+ e.stopPropagation()
1084
+ this.toggleAddProperty()
1073
1085
  }
1086
+ }
1074
1087
 
1075
- return result;
1076
- },
1077
- refreshValue: function() {
1078
- this.value = {};
1079
- var self = this;
1088
+ onChildEditorChange (editor, eventData) {
1089
+ this.refreshValue()
1090
+ super.onChildEditorChange(editor, eventData)
1091
+ }
1080
1092
 
1081
- for(var i in this.editors) {
1082
- if(!this.editors.hasOwnProperty(i)) continue;
1083
- if (this.editors[i].isActive()) {
1084
- this.value[i] = this.editors[i].getValue();
1085
- }
1093
+ canHaveAdditionalProperties () {
1094
+ // schemas have priority over options
1095
+ // local options have priority over global options
1096
+ // lastly global options are evaluated
1097
+
1098
+ // If the schema additionalProperties keyword is a boolean let the keyword decide
1099
+ if (typeof this.schema.additionalProperties === 'boolean') {
1100
+ return this.schema.additionalProperties
1086
1101
  }
1087
1102
 
1088
- if(this.adding_property) this.refreshAddProperties();
1089
- },
1090
- refreshAddProperties: function() {
1091
- if(this.options.disable_properties || (this.options.disable_properties !== false && this.jsoneditor.options.disable_properties)) {
1092
- this.addproperty_controls.style.display = 'none';
1093
- return;
1103
+ // If the schema additionalProperties keyword is a schema then additional properties are allowed and limited by such schema
1104
+ if (typeof this.schema.additionalProperties === 'object' && this.schema.additionalProperties !== null) {
1105
+ return true
1094
1106
  }
1095
1107
 
1096
- var can_add = false, can_remove = false, num_props = 0, i, show_modal = false;
1108
+ // If the schema options no_additional_properties is a boolean let the option decide
1109
+ if (typeof this.options.no_additional_properties === 'boolean') {
1110
+ return !this.options.no_additional_properties
1111
+ }
1097
1112
 
1098
- // Get number of editors
1099
- for(i in this.editors) {
1100
- if(!this.editors.hasOwnProperty(i)) continue;
1101
- num_props++;
1113
+ // If the global options no_additional_properties is a boolean let the option decide
1114
+ if (typeof this.jsoneditor.options.no_additional_properties === 'boolean') {
1115
+ return !this.jsoneditor.options.no_additional_properties
1102
1116
  }
1103
1117
 
1104
- // Determine if we can add back removed properties
1105
- can_add = this.canHaveAdditionalProperties() && !(typeof this.schema.maxProperties !== "undefined" && num_props >= this.schema.maxProperties);
1118
+ return true
1119
+ }
1120
+
1121
+ destroy () {
1122
+ Object.values(this.cached_editors).forEach(el => el.destroy())
1123
+ if (this.editor_holder) this.editor_holder.innerHTML = ''
1124
+ if (this.title && this.title.parentNode) this.title.parentNode.removeChild(this.title)
1125
+ if (this.error_holder && this.error_holder.parentNode) this.error_holder.parentNode.removeChild(this.error_holder)
1126
+
1127
+ this.editors = null
1128
+ this.cached_editors = null
1129
+ if (this.editor_holder && this.editor_holder.parentNode) this.editor_holder.parentNode.removeChild(this.editor_holder)
1130
+ this.editor_holder = null
1131
+ document.removeEventListener('click', this.onOutsideModalClickListener, true)
1132
+
1133
+ super.destroy()
1134
+ }
1106
1135
 
1107
- if(this.addproperty_checkboxes) {
1108
- this.addproperty_list.innerHTML = '';
1136
+ getValue () {
1137
+ if (!this.dependenciesFulfilled) {
1138
+ return undefined
1139
+ }
1140
+ const result = super.getValue()
1141
+ const isEmpty = obj => typeof obj === 'undefined' || obj === '' ||
1142
+ (
1143
+ obj === Object(obj) &&
1144
+ Object.keys(obj).length === 0 &&
1145
+ obj.constructor === Object
1146
+ )
1147
+ if (result && (this.jsoneditor.options.remove_empty_properties || this.options.remove_empty_properties)) {
1148
+ Object.keys(result).forEach(key => {
1149
+ if (isEmpty(result[key])) {
1150
+ delete result[key]
1151
+ }
1152
+ })
1109
1153
  }
1110
- this.addproperty_checkboxes = {};
1111
1154
 
1112
- // Check for which editors can't be removed or added back
1113
- for(i in this.cached_editors) {
1114
- if(!this.cached_editors.hasOwnProperty(i)) continue;
1155
+ if (result && (this.jsoneditor.options.remove_false_properties || this.options.remove_false_properties)) {
1156
+ Object.keys(result).forEach(key => {
1157
+ if (result[key] === false) {
1158
+ delete result[key]
1159
+ }
1160
+ })
1161
+ }
1162
+ return result
1163
+ }
1164
+
1165
+ refreshValue () {
1166
+ this.value = {}
1115
1167
 
1116
- this.addPropertyCheckbox(i);
1168
+ if (!this.editors) {
1169
+ return
1170
+ }
1117
1171
 
1118
- if(this.isRequired(this.cached_editors[i]) && i in this.editors) {
1119
- this.addproperty_checkboxes[i].disabled = true;
1172
+ Object.keys(this.editors).forEach(i => {
1173
+ if (this.editors[i].isActive()) {
1174
+ this.editors[i].refreshValue()
1175
+ this.value[i] = this.editors[i].getValue()
1120
1176
  }
1177
+ })
1121
1178
 
1122
- if(typeof this.schema.minProperties !== "undefined" && num_props <= this.schema.minProperties) {
1123
- this.addproperty_checkboxes[i].disabled = this.addproperty_checkboxes[i].checked;
1124
- if(!this.addproperty_checkboxes[i].checked) show_modal = true;
1179
+ Object.keys(this.editors).forEach(i => {
1180
+ if (this.editors[i].isActive()) {
1181
+ this.activateDependentRequired(this.editors[i].key)
1125
1182
  }
1126
- else if(!(i in this.editors)) {
1127
- if(!can_add && !this.schema.properties.hasOwnProperty(i)) {
1128
- this.addproperty_checkboxes[i].disabled = true;
1129
- }
1130
- else {
1131
- this.addproperty_checkboxes[i].disabled = false;
1132
- show_modal = true;
1183
+ })
1184
+
1185
+ if (this.adding_property) {
1186
+ this.refreshAddProperties()
1187
+ }
1188
+ }
1189
+
1190
+ activateDependentRequired (key) {
1191
+ const dependentRequired = this.getDependentRequired(key)
1192
+ dependentRequired.forEach((requiredProperty) => {
1193
+ let dependentRequiredEditor
1194
+
1195
+ Object.entries(this.cached_editors).forEach(([i, cachedEditor]) => {
1196
+ if (cachedEditor.key === requiredProperty) {
1197
+ dependentRequiredEditor = cachedEditor
1133
1198
  }
1199
+ })
1200
+
1201
+ if (dependentRequiredEditor && !dependentRequiredEditor.isActive()) {
1202
+ dependentRequiredEditor.activate()
1134
1203
  }
1135
- else {
1136
- show_modal = true;
1137
- can_remove = true;
1204
+ })
1205
+ }
1206
+
1207
+ getDependentRequired (property) {
1208
+ if (this.schema.dependentRequired) {
1209
+ if (hasOwnProperty(this.schema.dependentRequired, property)) {
1210
+ return this.schema.dependentRequired[property]
1138
1211
  }
1139
1212
  }
1140
1213
 
1141
- if(this.canHaveAdditionalProperties()) {
1142
- show_modal = true;
1143
- }
1214
+ return []
1215
+ }
1144
1216
 
1145
- // Additional addproperty checkboxes not tied to a current editor
1146
- for(i in this.schema.properties) {
1147
- if(!this.schema.properties.hasOwnProperty(i)) continue;
1148
- if(this.cached_editors[i]) continue;
1149
- show_modal = true;
1150
- this.addPropertyCheckbox(i);
1217
+ refreshAddProperties () {
1218
+ if (this.options.disable_properties || (this.options.disable_properties !== false && this.jsoneditor.options.disable_properties)) {
1219
+ this.addproperty_button.style.display = 'none'
1220
+ return
1151
1221
  }
1152
1222
 
1153
- // If no editors can be added or removed, hide the modal button
1154
- if(!show_modal) {
1155
- this.hideAddProperty();
1156
- this.addproperty_controls.style.display = 'none';
1157
- }
1158
- // If additional properties are disabled
1159
- else if(!this.canHaveAdditionalProperties()) {
1160
- this.addproperty_add.style.display = 'none';
1161
- this.addproperty_input.style.display = 'none';
1223
+ let canAdd = false; let numProps = 0; let showModal = false
1224
+
1225
+ /* Get number of editors */
1226
+ Object.keys(this.editors).forEach(i => numProps++)
1227
+
1228
+ /* Determine if we can add back removed properties */
1229
+ canAdd = this.canHaveAdditionalProperties() && !(typeof this.schema.maxProperties !== 'undefined' && numProps >= this.schema.maxProperties)
1230
+
1231
+ if (this.addproperty_checkboxes) {
1232
+ this.addproperty_list.innerHTML = ''
1162
1233
  }
1163
- // If no new properties can be added
1164
- else if(!can_add) {
1165
- this.addproperty_add.disabled = true;
1234
+ this.addproperty_checkboxes = {}
1235
+
1236
+ /* Check for which editors can't be removed or added back */
1237
+ Object.keys(this.cached_editors).forEach(i => {
1238
+ this.addPropertyCheckbox(i)
1239
+
1240
+ if (this.isRequiredObject(this.cached_editors[i]) && i in this.editors) {
1241
+ this.addproperty_checkboxes[i].disabled = true
1242
+ }
1243
+
1244
+ if (typeof this.schema.minProperties !== 'undefined' && numProps <= this.schema.minProperties) {
1245
+ this.addproperty_checkboxes[i].disabled = this.addproperty_checkboxes[i].checked
1246
+ if (!this.addproperty_checkboxes[i].checked) showModal = true
1247
+ } else if (!(i in this.editors)) {
1248
+ if (!canAdd && !hasOwnProperty(this.schema.properties, i)) {
1249
+ this.addproperty_checkboxes[i].disabled = true
1250
+ } else {
1251
+ this.addproperty_checkboxes[i].disabled = false
1252
+ showModal = true
1253
+ }
1254
+ } else {
1255
+ showModal = true
1256
+ }
1257
+ })
1258
+
1259
+ if (this.canHaveAdditionalProperties()) {
1260
+ showModal = true
1166
1261
  }
1167
- // If new properties can be added
1168
- else {
1169
- this.addproperty_add.disabled = false;
1262
+
1263
+ /* Additional addproperty checkboxes not tied to a current editor */
1264
+ Object.keys(this.schema.properties).forEach(i => {
1265
+ if (this.cached_editors[i]) return
1266
+ showModal = true
1267
+ this.addPropertyCheckbox(i)
1268
+ })
1269
+
1270
+ /* If no editors can be added or removed, hide the modal button */
1271
+ if (!showModal) {
1272
+ this.hideAddProperty()
1273
+ this.addproperty_button.style.display = 'none'
1274
+ /* If additional properties are disabled */
1275
+ } else if (!this.canHaveAdditionalProperties()) {
1276
+ this.addproperty_add.style.display = 'none'
1277
+ this.addproperty_input.style.display = 'none'
1278
+ /* If no new properties can be added */
1279
+ } else if (!canAdd) {
1280
+ this.addproperty_add.disabled = true
1281
+ /* If new properties can be added */
1282
+ } else {
1283
+ this.addproperty_add.disabled = false
1170
1284
  }
1171
- },
1172
- isRequired: function(editor) {
1285
+ }
1286
+
1287
+ isRequiredObject (editor) {
1173
1288
  if (!editor) {
1174
- return;
1289
+ return
1175
1290
  }
1176
- if(typeof editor.schema.required === "boolean") return editor.schema.required;
1177
- else if(Array.isArray(this.schema.required)) return this.schema.required.indexOf(editor.key) > -1;
1178
- else if(this.jsoneditor.options.required_by_default) return true;
1179
- else return false;
1180
- },
1181
- setValue: function(value, initial) {
1182
- var self = this;
1183
- value = value || {};
1184
-
1185
- if(typeof value !== "object" || Array.isArray(value)) value = {};
1186
-
1187
- // First, set the values for all of the defined properties
1188
- $each(this.cached_editors, function(i,editor) {
1189
- // Value explicitly set
1190
- if(typeof value[i] !== "undefined") {
1191
- self.addObjectProperty(i);
1192
- editor.setValue(value[i],initial);
1193
- }
1194
- // Otherwise, remove value unless this is the initial set or it's required
1195
- else if(!initial && !self.isRequired(editor)) {
1196
- self.removeObjectProperty(i);
1197
- }
1198
- // Otherwise, set the value to the default
1199
- else {
1200
- editor.setValue(editor.getDefault(),initial);
1201
- }
1202
- });
1203
1291
 
1204
- $each(value, function(i,val) {
1205
- if(!self.cached_editors[i]) {
1206
- self.addObjectProperty(i);
1207
- if(self.editors[i]) self.editors[i].setValue(val,initial);
1208
- }
1209
- });
1210
-
1211
- this.refreshValue();
1212
- this.layoutEditors();
1213
- this.onChange();
1214
- },
1215
- showValidationErrors: function(errors) {
1216
- var self = this;
1217
-
1218
- // Get all the errors that pertain to this editor
1219
- var my_errors = [];
1220
- var other_errors = [];
1221
- $each(errors, function(i,error) {
1222
- if(error.path === self.path) {
1223
- my_errors.push(error);
1292
+ if (typeof editor.schema.required === 'boolean') return editor.schema.required
1293
+ else if (Array.isArray(this.schema.required)) return this.schema.required.includes(editor.key)
1294
+ else if (this.jsoneditor.options.required_by_default) return true
1295
+ return false
1296
+ }
1297
+
1298
+ setValue (value, initial) {
1299
+ value = this.applyConstFilter(value)
1300
+
1301
+ value = value || {}
1302
+
1303
+ if (typeof value !== 'object' || Array.isArray(value)) value = {}
1304
+
1305
+ /* First, set the values for all of the defined properties */
1306
+ Object.entries(this.cached_editors).forEach(([i, editor]) => {
1307
+ /* Value explicitly set */
1308
+ if (typeof value[i] !== 'undefined') {
1309
+ this.addObjectProperty(i)
1310
+ editor.setValue(value[i], initial)
1311
+ editor.activate()
1312
+ if (this.disabled) {
1313
+ editor.disable()
1314
+ }
1315
+ /* Otherwise, remove value unless this is the initial set or it's required */
1316
+ } else if (!initial && !this.isRequiredObject(editor)) {
1317
+ if (this.jsoneditor.options.show_opt_in || this.options.show_opt_in) {
1318
+ editor.deactivate()
1319
+ } else {
1320
+ this.removeObjectProperty(i)
1321
+ }
1322
+ /* Otherwise, set the value to the default */
1323
+ } else {
1324
+ editor.setValue(editor.getDefault(), initial)
1224
1325
  }
1225
- else {
1226
- other_errors.push(error);
1326
+ })
1327
+
1328
+ Object.entries(value).forEach(([i, val]) => {
1329
+ if (!this.cached_editors[i]) {
1330
+ this.addObjectProperty(i)
1331
+ if (this.editors[i]) this.editors[i].setValue(val, initial, !!this.editors[i].template)
1227
1332
  }
1228
- });
1229
-
1230
- // Show errors for this editor
1231
- if(this.error_holder) {
1232
- if(my_errors.length) {
1233
- var message = [];
1234
- this.error_holder.innerHTML = '';
1235
- this.error_holder.style.display = '';
1236
- $each(my_errors, function(i,error) {
1237
- self.error_holder.appendChild(self.theme.getErrorMessage(error.message));
1238
- });
1333
+ })
1334
+
1335
+ this.refreshValue()
1336
+ this.layoutEditors()
1337
+ this.onChange()
1338
+ }
1339
+
1340
+ showValidationErrors (errors) {
1341
+ /* Get all the errors that pertain to this editor */
1342
+ const myErrors = []
1343
+ const otherErrors = []
1344
+ errors.forEach(error => {
1345
+ if (error.path === this.path) {
1346
+ myErrors.push(error)
1347
+ } else {
1348
+ otherErrors.push(error)
1239
1349
  }
1240
- // Hide error area
1241
- else {
1242
- this.error_holder.style.display = 'none';
1350
+ })
1351
+
1352
+ /* Show errors for this editor */
1353
+ if (this.error_holder) {
1354
+ if (myErrors.length) {
1355
+ this.error_holder.innerHTML = ''
1356
+ this.error_holder.style.display = ''
1357
+ myErrors.forEach(error => {
1358
+ if (error.errorcount && error.errorcount > 1) error.message += ` (${error.errorcount} errors)`
1359
+ this.error_holder.appendChild(this.theme.getErrorMessage(error.message))
1360
+ })
1361
+ /* Hide error area */
1362
+ } else {
1363
+ this.error_holder.style.display = 'none'
1243
1364
  }
1244
1365
  }
1245
1366
 
1246
- // Show error for the table row if this is inside a table
1247
- if(this.options.table_row) {
1248
- if(my_errors.length) {
1249
- this.theme.addTableRowError(this.container);
1250
- }
1251
- else {
1252
- this.theme.removeTableRowError(this.container);
1367
+ /* Show error for the table row if this is inside a table */
1368
+ if (this.options.table_row) {
1369
+ if (myErrors.length) {
1370
+ this.theme.addTableRowError(this.container)
1371
+ } else {
1372
+ this.theme.removeTableRowError(this.container)
1253
1373
  }
1254
1374
  }
1255
1375
 
1256
- // Show errors for child editors
1257
- $each(this.editors, function(i,editor) {
1258
- editor.showValidationErrors(other_errors);
1259
- });
1376
+ /* Show errors for child editors */
1377
+ Object.values(this.editors).forEach(editor => {
1378
+ editor.showValidationErrors(otherErrors)
1379
+ })
1260
1380
  }
1261
- });
1381
+ }
1382
+
1383
+ ObjectEditor.rules = rules