@json-editor/json-editor 2.15.0 → 2.15.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/.env +0 -4
  2. package/.github/workflows/build.yml +5 -5
  3. package/CHANGELOG.md +19 -0
  4. package/README.md +16 -0
  5. package/config/codeceptjs_helpers.js +11 -0
  6. package/dist/jsoneditor.js +1 -1
  7. package/dist/jsoneditor.js.LICENSE.txt +1 -1
  8. package/dist/nonmin/jsoneditor.js +502 -152
  9. package/dist/nonmin/jsoneditor.js.map +1 -1
  10. package/package.json +1 -1
  11. package/src/core.js +11 -0
  12. package/src/defaults.js +2 -1
  13. package/src/editor.js +26 -15
  14. package/src/editors/ace.js +1 -0
  15. package/src/editors/array/choices.js +1 -0
  16. package/src/editors/array/select2.js +2 -0
  17. package/src/editors/array/selectize.js +2 -0
  18. package/src/editors/array.js +81 -0
  19. package/src/editors/base64.js +2 -0
  20. package/src/editors/checkbox.js +13 -1
  21. package/src/editors/choices.js +2 -0
  22. package/src/editors/colorpicker.js +2 -0
  23. package/src/editors/datetime.js +2 -0
  24. package/src/editors/describedby.js +2 -0
  25. package/src/editors/enum.js +3 -1
  26. package/src/editors/hidden.js +2 -0
  27. package/src/editors/jodit.js +2 -0
  28. package/src/editors/multiple.js +2 -0
  29. package/src/editors/multiselect.js +2 -0
  30. package/src/editors/object.js +10 -3
  31. package/src/editors/radio.js +2 -0
  32. package/src/editors/sceditor.js +2 -0
  33. package/src/editors/select.js +9 -4
  34. package/src/editors/select2.js +2 -0
  35. package/src/editors/selectize.js +2 -0
  36. package/src/editors/signature.js +2 -0
  37. package/src/editors/simplemde.js +3 -1
  38. package/src/editors/starrating.js +2 -0
  39. package/src/editors/string.js +2 -0
  40. package/src/editors/table.js +19 -2
  41. package/src/editors/upload.js +2 -0
  42. package/src/editors/uuid.js +2 -0
  43. package/src/resolvers.js +1 -1
  44. package/src/theme.js +23 -0
  45. package/src/themes/bootstrap3.css +53 -0
  46. package/src/themes/bootstrap3.css.js +1 -1
  47. package/src/themes/bootstrap3.js +30 -0
  48. package/src/themes/bootstrap4.js +27 -0
  49. package/src/themes/bootstrap5.js +28 -0
  50. package/src/themes/spectre.js +28 -0
  51. package/src/themes/tailwind.css +54 -0
  52. package/src/themes/tailwind.css.js +1 -1
  53. package/src/themes/tailwind.js +26 -0
  54. package/tests/codeceptjs/core_test.js +28 -0
  55. package/tests/codeceptjs/editors/integer_test.js +3 -1
  56. package/tests/codeceptjs/editors/multiple_test.js +27 -0
  57. package/tests/codeceptjs/editors/select_test.js +12 -0
  58. package/tests/codeceptjs/issues/issue-gh-1562_test.js +12 -0
  59. package/tests/codeceptjs/issues/issue-gh-1586_test.js +15 -0
  60. package/tests/docker-compose-local.yml +2 -1
  61. package/tests/pages/editor-show-validation-errors.html +54 -0
  62. package/tests/pages/enforce-const.html +10 -18
  63. package/tests/pages/integer.html +9 -10
  64. package/tests/pages/issues/issue-gh-1562.html +170 -0
  65. package/tests/pages/issues/issue-gh-1586.html +48 -0
  66. package/tests/pages/opt-in-widget.html +134 -0
  67. package/tests/pages/select-values.html +91 -0
  68. package/tests/pages/switcher-option.html +69 -0
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@json-editor/json-editor",
3
3
  "title": "JSONEditor",
4
4
  "description": "JSON Schema based editor",
5
- "version": "2.15.0",
5
+ "version": "2.15.2",
6
6
  "main": "dist/jsoneditor.js",
7
7
  "author": {
8
8
  "name": "Jeremy Dorn",
package/src/core.js CHANGED
@@ -411,6 +411,17 @@ export class JSONEditor {
411
411
  styleSheet.replaceSync(cssText)
412
412
  shadowRoot.adoptedStyleSheets = [...shadowRoot.adoptedStyleSheets, styleSheet]
413
413
  }
414
+
415
+ showValidationErrors (errorList) {
416
+ const errors = errorList ?? this.validate()
417
+
418
+ Object.values(this.editors).forEach(editor => {
419
+ if (editor) {
420
+ editor.is_dirty = true
421
+ editor.showValidationErrors(errors)
422
+ }
423
+ })
424
+ }
414
425
  }
415
426
 
416
427
  JSONEditor.defaults = defaults
package/src/defaults.js CHANGED
@@ -420,7 +420,8 @@ const options = {
420
420
  show_errors: 'interaction',
421
421
  prompt_paste_max_length_reached: false,
422
422
  remove_false_properties: false,
423
- enforce_const: false
423
+ enforce_const: false,
424
+ opt_in_widget: 'checkbox'
424
425
  }
425
426
 
426
427
  /* This assignment was previously in index.js but makes more sense here */
package/src/editor.js CHANGED
@@ -17,7 +17,7 @@ export class AbstractEditor {
17
17
  this.active = true
18
18
  this.isUiOnly = false
19
19
  this.options = extend({}, (this.options || {}), (this.schema.options || {}), (options.schema.options || {}), options)
20
- this.enforceConst = this.options.enforce_const ?? this.jsoneditor.options.enforce_const
20
+ this.enforceConstEnabled = this.options.enforce_const ?? this.jsoneditor.options.enforce_const
21
21
  this.formname = this.jsoneditor.options.form_name_root || 'root'
22
22
 
23
23
  if (!options.path && !this.schema.id) this.schema.id = this.formname
@@ -29,6 +29,7 @@ export class AbstractEditor {
29
29
 
30
30
  this.link_watchers = []
31
31
  this.watchLoop = false
32
+ this.optInWidget = this.options.opt_in_widget ?? this.jsoneditor.options.opt_in_widget
32
33
 
33
34
  if (options.container) this.setContainer(options.container)
34
35
  this.registerDependencies()
@@ -216,16 +217,17 @@ export class AbstractEditor {
216
217
  this.container.setAttribute('data-schemapath', this.path)
217
218
  }
218
219
 
219
- setOptInCheckbox (header) {
220
- /* the active/deactive checbox control. */
220
+ setOptInCheckbox () {
221
+ let optIn
221
222
 
222
- this.optInLabel = this.theme.getHiddenLabel(this.formname + ' opt-in')
223
- this.optInLabel.setAttribute('for', this.formname + '-opt-in')
224
- this.optInCheckbox = document.createElement('input')
225
- this.optInCheckbox.setAttribute('type', 'checkbox')
226
- this.optInCheckbox.setAttribute('style', 'margin: 0 10px 0 0;')
227
- this.optInCheckbox.setAttribute('id', this.formname + '-opt-in')
228
- this.optInCheckbox.classList.add('json-editor-opt-in')
223
+ if (this.optInWidget === 'switch') {
224
+ optIn = this.theme.getOptInSwitch(this.formname)
225
+ } else {
226
+ optIn = this.theme.getOptInCheckbox(this.formname)
227
+ }
228
+
229
+ this.optInCheckbox = optIn.checkbox
230
+ this.optInContainer = optIn.container
229
231
 
230
232
  this.optInCheckbox.addEventListener('click', () => {
231
233
  if (this.isActive()) {
@@ -240,12 +242,12 @@ export class AbstractEditor {
240
242
  const parentOptInDefined = (typeof this.parent.options.show_opt_in !== 'undefined')
241
243
  const parentOptInEnabled = (parentOptInDefined && this.parent.options.show_opt_in === true)
242
244
  const parentOptInDisabled = (parentOptInDefined && this.parent.options.show_opt_in === false)
245
+
243
246
  if (parentOptInEnabled || (!parentOptInDisabled && globalOptIn) || (!parentOptInDefined && globalOptIn)) {
244
247
  /* and control to type object editors if they are not required */
245
248
  if (this.parent && this.parent.schema.type === 'object' && !this.isRequired() && this.header) {
246
- this.header.appendChild(this.optInLabel)
247
- this.header.appendChild(this.optInCheckbox)
248
- this.header.insertBefore(this.optInCheckbox, this.header.firstChild)
249
+ this.header.insertBefore(this.optInContainer, this.header.firstChild)
250
+ this.optInAppended = true
249
251
  }
250
252
  }
251
253
  }
@@ -271,7 +273,7 @@ export class AbstractEditor {
271
273
  this.theme.visuallyHidden(this.header)
272
274
  }
273
275
 
274
- if (this.enforceConst && this.schema.const) {
276
+ if (this.enforceConstEnabled && this.schema.const) {
275
277
  this.disable()
276
278
  }
277
279
  }
@@ -583,9 +585,18 @@ export class AbstractEditor {
583
585
  }
584
586
 
585
587
  setValue (value) {
588
+ value = this.applyConstFilter(value)
586
589
  this.value = value
587
590
  }
588
591
 
592
+ applyConstFilter (value) {
593
+ if (this.enforceConstEnabled && typeof this.schema.const !== 'undefined') {
594
+ value = this.schema.const
595
+ }
596
+
597
+ return value
598
+ }
599
+
589
600
  getValue () {
590
601
  if (!this.dependenciesFulfilled) {
591
602
  return undefined
@@ -627,7 +638,7 @@ export class AbstractEditor {
627
638
  }
628
639
 
629
640
  getDefault () {
630
- if (this.enforceConst && this.schema.const) {
641
+ if (this.enforceConstEnabled && this.schema.const) {
631
642
  return this.schema.const
632
643
  }
633
644
 
@@ -3,6 +3,7 @@ import { extend } from '../utilities.js'
3
3
 
4
4
  export class AceEditor extends StringEditor {
5
5
  setValue (value, initial, fromTemplate) {
6
+ value = this.applyConstFilter(value)
6
7
  const res = super.setValue(value, initial, fromTemplate)
7
8
  if (res !== undefined && res.changed && this.ace_editor_instance) {
8
9
  this.ace_editor_instance.setValue(res.value)
@@ -4,6 +4,7 @@ import { extend } from '../../utilities.js'
4
4
  export class ArrayChoicesEditor extends MultiSelectEditor {
5
5
  setValue (value, initial) {
6
6
  if (this.choices_instance) {
7
+ value = this.applyConstFilter(value)
7
8
  /* Make sure we are dealing with an array of strings so we can check for strict equality */
8
9
  value = [].concat(value).map(e => `${e}`)
9
10
 
@@ -3,6 +3,8 @@ import { extend, hasOwnProperty } from '../../utilities.js'
3
3
 
4
4
  export class ArraySelect2Editor extends MultiSelectEditor {
5
5
  setValue (value, initial) {
6
+ value = this.applyConstFilter(value)
7
+
6
8
  if (this.select2_instance) {
7
9
  /* Make sure we are dealing with an array of strings so we can check for strict equality */
8
10
  value = [].concat(value).map(e => `${e}`)
@@ -3,6 +3,8 @@ import { extend } from '../../utilities.js'
3
3
 
4
4
  export class ArraySelectizeEditor extends MultiSelectEditor {
5
5
  setValue (value, initial) {
6
+ value = this.applyConstFilter(value)
7
+
6
8
  if (this.selectize_instance) {
7
9
  /* Make sure we are dealing with an array of strings so we can check for strict equality */
8
10
  value = [].concat(value).map(e => `${e}`)
@@ -163,6 +163,7 @@ export class ArrayEditor extends AbstractEditor {
163
163
  onChildEditorChange (editor, eventData) {
164
164
  this.refreshValue()
165
165
  this.refreshTabs(true)
166
+ this.is_dirty = true
166
167
  super.onChildEditorChange(editor, eventData)
167
168
  }
168
169
 
@@ -348,6 +349,7 @@ export class ArrayEditor extends AbstractEditor {
348
349
  }
349
350
 
350
351
  setValue (value = [], initial) {
352
+ value = this.applyConstFilter(value)
351
353
  /* Make sure value has between minItems and maxItems items in it */
352
354
  value = this.ensureArraySize(value)
353
355
 
@@ -500,6 +502,9 @@ export class ArrayEditor extends AbstractEditor {
500
502
  e.preventDefault()
501
503
  e.stopPropagation()
502
504
  })
505
+ this._supportDragDrop(this.rows[i].tab)
506
+ } else {
507
+ this._supportDragDrop(this.rows[i].container, true)
503
508
  }
504
509
 
505
510
  const controlsHolder = this.rows[i].title_controls || this.rows[i].array_controls
@@ -666,6 +671,23 @@ export class ArrayEditor extends AbstractEditor {
666
671
  return button
667
672
  }
668
673
 
674
+ _supportDragDrop (tab, useTrigger) {
675
+ supportDragDrop(tab, (i, j) => {
676
+ const rows = this.getValue()
677
+ const tmp = rows[i]
678
+ rows.splice(i, 1)
679
+ rows.splice(j, 0, tmp)
680
+
681
+ this.setValue(rows)
682
+ this.active_tab = this.rows[j].tab
683
+ this.refreshTabs()
684
+
685
+ this.onChange(true)
686
+
687
+ this.jsoneditor.trigger('moveRow', this.rows[j])
688
+ }, { useTrigger })
689
+ }
690
+
669
691
  addControls () {
670
692
  this.collapsed = false
671
693
  this.toggle_button = this._createToggleButton()
@@ -732,6 +754,10 @@ export class ArrayEditor extends AbstractEditor {
732
754
  if (this.row_cache[i]) {
733
755
  editor = this.rows[i] = this.row_cache[i]
734
756
  this.rows[i].setValue(this.rows[i].getDefault(), true)
757
+ // override cached value, so optional properties are not checked.
758
+ if (typeof this.rows[i].deactivateNonRequiredProperties === 'function') {
759
+ this.rows[i].deactivateNonRequiredProperties(true)
760
+ }
735
761
  this.rows[i].container.style.display = ''
736
762
  if (this.rows[i].tab) this.rows[i].tab.style.display = ''
737
763
  this.rows[i].register()
@@ -837,3 +863,58 @@ export class ArrayEditor extends AbstractEditor {
837
863
  }
838
864
  }
839
865
  ArrayEditor.rules = rules
866
+
867
+ // drag/drop array item to adjust order
868
+ // handler(fromIdx, toIdx, fromDom, toDom), opt={useTrigger}
869
+ // useTrigger=true: pressing ctrl to enable drag
870
+ export function supportDragDrop (tab, handler, opt = {}) {
871
+ if (opt.useTrigger) {
872
+ tab.addEventListener('mousedown', e => {
873
+ if (e.ctrlKey) {
874
+ // window.console.log('enable drag')
875
+ tab.draggable = true
876
+ const fn = e => {
877
+ tab.draggable = false
878
+ // window.console.log('disable drag')
879
+ document.removeEventListener('dragend', fn)
880
+ document.removeEventListener('mouseup', fn)
881
+ }
882
+ document.addEventListener('dragend', fn)
883
+ document.addEventListener('mouseup', fn)
884
+ }
885
+ })
886
+ } else {
887
+ tab.draggable = true
888
+ }
889
+ tab.addEventListener('dragstart', e => {
890
+ window.curDrag = tab
891
+ })
892
+ tab.addEventListener('dragover', e => {
893
+ if (window.curDrag === null || window.curDrag === tab || window.curDrag.parentElement !== tab.parentElement) {
894
+ e.dataTransfer.dropEffect = 'none'
895
+ } else {
896
+ e.dataTransfer.dropEffect = 'move'
897
+ }
898
+ e.preventDefault()
899
+ })
900
+ tab.addEventListener('drop', e => {
901
+ e.preventDefault()
902
+ e.stopPropagation()
903
+ if (window.curDrag === null || window.curDrag === tab || window.curDrag.parentElement !== tab.parentElement) {
904
+ return
905
+ }
906
+ const getPos = item => {
907
+ let i = 0
908
+ let a = item.parentElement.firstElementChild
909
+ while (a !== item && a !== null) {
910
+ a = a.nextSibling
911
+ ++i
912
+ }
913
+ return i
914
+ }
915
+ const i = getPos(window.curDrag)
916
+ const j = getPos(tab)
917
+ handler(i, j, window.curDrag, tab)
918
+ window.curDrag = null
919
+ })
920
+ }
@@ -149,6 +149,8 @@ export class Base64Editor extends AbstractEditor {
149
149
  }
150
150
 
151
151
  setValue (val) {
152
+ val = this.applyConstFilter(val)
153
+
152
154
  if (this.value !== val) {
153
155
  if (this.schema.readOnly && this.schema.enum && !this.schema.enum.includes(val)) this.value = this.schema.enum[0]
154
156
  else this.value = val
@@ -2,6 +2,7 @@ import { AbstractEditor } from '../editor.js'
2
2
 
3
3
  export class CheckboxEditor extends AbstractEditor {
4
4
  setValue (value, initial) {
5
+ value = this.applyConstFilter(value)
5
6
  value = !!value
6
7
  const changed = this.getValue() !== value
7
8
  this.value = value
@@ -32,6 +33,16 @@ export class CheckboxEditor extends AbstractEditor {
32
33
  return Math.min(12, Math.max(this.getTitle().length / 7, 2))
33
34
  }
34
35
 
36
+ setOptInCheckbox () {
37
+ super.setOptInCheckbox()
38
+
39
+ if (this.optInAppended) {
40
+ this.container.insertBefore(this.optInContainer, this.container.firstChild)
41
+ this.optInContainer.style.verticalAlign = 'top'
42
+ this.control.style.marginTop = '0'
43
+ }
44
+ }
45
+
35
46
  build () {
36
47
  if (!this.parent.options.table_row) {
37
48
  this.label = this.header = this.theme.getCheckboxLabel(this.getTitle(), this.isRequired())
@@ -45,6 +56,7 @@ export class CheckboxEditor extends AbstractEditor {
45
56
  this.input = this.theme.getCheckbox()
46
57
  this.input.id = this.formname
47
58
  this.control = this.theme.getFormControl(this.label, this.input, this.description, this.infoButton)
59
+ this.control.style.display = 'inline-block'
48
60
 
49
61
  if (this.schema.readOnly || this.schema.readonly) {
50
62
  this.disable(true)
@@ -87,7 +99,7 @@ export class CheckboxEditor extends AbstractEditor {
87
99
  const changeOrInteraction = showErrors === 'change' || showErrors === 'interaction'
88
100
  const never = showErrors === 'never'
89
101
 
90
- if (never) {
102
+ if (never && !this.is_dirty) {
91
103
  return
92
104
  }
93
105
 
@@ -4,6 +4,8 @@ import rules from './choices.css.js'
4
4
 
5
5
  export class ChoicesEditor extends SelectEditor {
6
6
  setValue (value, initial) {
7
+ value = this.applyConstFilter(value)
8
+
7
9
  if (this.choices_instance) {
8
10
  /* Sanitize value before setting it */
9
11
  let sanitized = this.typecast(value || '')
@@ -17,6 +17,8 @@ export class ColorEditor extends StringEditor {
17
17
  }
18
18
 
19
19
  setValue (value, initial, fromTemplate) {
20
+ value = this.applyConstFilter(value)
21
+
20
22
  const res = super.setValue(value, initial, fromTemplate)
21
23
  if (this.picker_instance && this.picker_instance.domElement && res && res.changed) {
22
24
  this.picker_instance.setColor(res.value, true)
@@ -104,6 +104,8 @@ export class DatetimeEditor extends StringEditor {
104
104
  }
105
105
 
106
106
  setValue (value, initial, fromTemplate) {
107
+ value = this.applyConstFilter(value)
108
+
107
109
  if (this.schema.type === 'string') {
108
110
  super.setValue(value, initial, fromTemplate)
109
111
  if (this.flatpickr) this.flatpickr.setDate(value)
@@ -160,6 +160,8 @@ export class DescribedByEditor extends AbstractEditor {
160
160
  }
161
161
 
162
162
  setValue (val, initial) {
163
+ val = this.applyConstFilter(val)
164
+
163
165
  if (this.editors[this.currentEditor]) {
164
166
  this.editors[this.currentEditor].setValue(val, initial)
165
167
  this.refreshValue()
@@ -12,7 +12,7 @@ export class EnumEditor extends AbstractEditor {
12
12
 
13
13
  this.options.enum_titles = this.options.enum_titles || []
14
14
 
15
- if (this.enforceConst && this.schema.const) {
15
+ if (this.enforceConstEnabled && this.schema.const) {
16
16
  this.enum = [this.schema.const]
17
17
  } else {
18
18
  this.enum = this.schema.enum
@@ -127,6 +127,8 @@ export class EnumEditor extends AbstractEditor {
127
127
  }
128
128
 
129
129
  setValue (val) {
130
+ val = this.applyConstFilter(val)
131
+
130
132
  if (this.value !== val) {
131
133
  this.value = val
132
134
  this.refreshValue()
@@ -19,6 +19,8 @@ export class HiddenEditor extends AbstractEditor {
19
19
  }
20
20
 
21
21
  setValue (value, initial, fromTemplate) {
22
+ value = this.applyConstFilter(value)
23
+
22
24
  if (this.template && !fromTemplate) {
23
25
  return
24
26
  }
@@ -3,6 +3,8 @@ import { extend } from '../utilities.js'
3
3
 
4
4
  export class JoditEditor extends StringEditor {
5
5
  setValue (value, initial, fromTemplate) {
6
+ value = this.applyConstFilter(value)
7
+
6
8
  const res = super.setValue(value, initial, fromTemplate)
7
9
  if (res !== undefined && res.changed && this.jodit_instance) this.jodit_instance.setEditorValue(res.value)
8
10
  }
@@ -319,6 +319,8 @@ export class MultipleEditor extends AbstractEditor {
319
319
  }
320
320
 
321
321
  setValue (val, initial) {
322
+ val = this.applyConstFilter(val)
323
+
322
324
  /* Determine type by getting the first one that validates */
323
325
 
324
326
  const prevType = this.type
@@ -132,6 +132,8 @@ export class MultiSelectEditor extends AbstractEditor {
132
132
  }
133
133
 
134
134
  setValue (value, initial) {
135
+ value = this.applyConstFilter(value)
136
+
135
137
  value = value || []
136
138
  if (!(Array.isArray(value))) value = [value]
137
139
 
@@ -41,7 +41,9 @@ export class ObjectEditor extends AbstractEditor {
41
41
  if (e.isActive() || e.isUiOnly) {
42
42
  e.enable()
43
43
  }
44
- e.optInCheckbox.disabled = false
44
+ if (e.optInCheckbox) {
45
+ e.optInCheckbox.disabled = false
46
+ }
45
47
  })
46
48
  }
47
49
  }
@@ -802,7 +804,7 @@ export class ObjectEditor extends AbstractEditor {
802
804
  this.refreshAddProperties()
803
805
 
804
806
  /* non required properties start deactivated */
805
- this.deactivateNonRequiredProperties()
807
+ this.deactivateNonRequiredProperties(false)
806
808
  }
807
809
 
808
810
  /* Fix table cell ordering */
@@ -824,7 +826,7 @@ export class ObjectEditor extends AbstractEditor {
824
826
  }
825
827
  }
826
828
 
827
- deactivateNonRequiredProperties () {
829
+ deactivateNonRequiredProperties (recursive) {
828
830
  /* the show_opt_in editor option is for backward compatibility */
829
831
  const globalOptIn = this.jsoneditor.options.show_opt_in
830
832
  const editorOptInDefined = (typeof this.options.show_opt_in !== 'undefined')
@@ -835,6 +837,9 @@ export class ObjectEditor extends AbstractEditor {
835
837
  if (!this.isRequiredObject(editor)) {
836
838
  this.editors[key].deactivate()
837
839
  }
840
+ if (recursive && typeof this.editors[key].deactivateNonRequiredProperties === 'function') {
841
+ this.editors[key].deactivateNonRequiredProperties(recursive)
842
+ }
838
843
  })
839
844
  }
840
845
  }
@@ -1291,6 +1296,8 @@ export class ObjectEditor extends AbstractEditor {
1291
1296
  }
1292
1297
 
1293
1298
  setValue (value, initial) {
1299
+ value = this.applyConstFilter(value)
1300
+
1294
1301
  value = value || {}
1295
1302
 
1296
1303
  if (typeof value !== 'object' || Array.isArray(value)) value = {}
@@ -107,6 +107,8 @@ export class RadioEditor extends SelectEditor {
107
107
  }
108
108
 
109
109
  setValue (val) {
110
+ val = this.applyConstFilter(val)
111
+
110
112
  if (typeof val !== 'string') {
111
113
  val = String(val)
112
114
  }
@@ -3,6 +3,8 @@ import { extend } from '../utilities.js'
3
3
 
4
4
  export class ScEditor extends StringEditor {
5
5
  setValue (value, initial, fromTemplate) {
6
+ value = this.applyConstFilter(value)
7
+
6
8
  const res = super.setValue(value, initial, fromTemplate)
7
9
  if (res !== undefined && res.changed && this.sceditor_instance) this.sceditor_instance.val(res.value)
8
10
  }
@@ -3,6 +3,7 @@ import { extend } from '../utilities.js'
3
3
 
4
4
  export class SelectEditor extends AbstractEditor {
5
5
  setValue (value, initial) {
6
+ value = this.applyConstFilter(value)
6
7
  /* Sanitize value before setting it */
7
8
  let sanitized = this.typecast(value)
8
9
  const inEnum = (this.enum_options.length > 0 && this.enum_values.includes(sanitized))
@@ -15,10 +16,14 @@ export class SelectEditor extends AbstractEditor {
15
16
 
16
17
  if (this.value === sanitized) return
17
18
 
18
- if (inEnum && this.hasPlaceholderOption) {
19
- this.input.value = this.enum_options[this.enum_values.indexOf(sanitized)]
20
- } else {
19
+ const selectedIndex = this.enum_values.indexOf(sanitized)
20
+
21
+ if (inEnum && selectedIndex !== -1) {
22
+ this.input.value = this.enum_options[selectedIndex]
23
+ } else if (this.hasPlaceholderOption) {
21
24
  this.input.value = '_placeholder_'
25
+ } else {
26
+ this.input.value = sanitized
22
27
  }
23
28
 
24
29
  this.value = sanitized
@@ -362,7 +367,7 @@ export class SelectEditor extends AbstractEditor {
362
367
  const changeOrInteraction = showErrors === 'change' || showErrors === 'interaction'
363
368
  const never = showErrors === 'never'
364
369
 
365
- if (never) {
370
+ if (never && !this.is_dirty) {
366
371
  return
367
372
  }
368
373
 
@@ -3,6 +3,8 @@ import { extend, hasOwnProperty } from '../utilities.js'
3
3
 
4
4
  export class Select2Editor extends SelectEditor {
5
5
  setValue (value, initial) {
6
+ value = this.applyConstFilter(value)
7
+
6
8
  if (this.select2_instance) {
7
9
  if (initial) this.is_dirty = false
8
10
  else if (this.jsoneditor.options.show_errors === 'change') this.is_dirty = true
@@ -3,6 +3,8 @@ import { extend } from '../utilities.js'
3
3
 
4
4
  export class SelectizeEditor extends SelectEditor {
5
5
  setValue (value, initial) {
6
+ value = this.applyConstFilter(value)
7
+
6
8
  if (this.selectize_instance) {
7
9
  if (initial) this.is_dirty = false
8
10
  else if (this.jsoneditor.options.show_errors === 'change') this.is_dirty = true
@@ -90,6 +90,8 @@ export class SignatureEditor extends StringEditor {
90
90
  }
91
91
 
92
92
  setValue (val) {
93
+ val = this.applyConstFilter(val)
94
+
93
95
  if (typeof SignaturePad === 'function') {
94
96
  const sanitized = this.sanitize(val)
95
97
  if (this.value === sanitized) {
@@ -3,6 +3,8 @@ import { extend } from '../utilities.js'
3
3
 
4
4
  export class SimplemdeEditor extends StringEditor {
5
5
  setValue (value, initial, fromTemplate) {
6
+ value = this.applyConstFilter(value)
7
+
6
8
  const res = super.setValue(value, initial, fromTemplate)
7
9
  if (res !== undefined && res.changed && this.simplemde_instance) this.simplemde_instance.value(res.value)
8
10
  }
@@ -74,7 +76,7 @@ export class SimplemdeEditor extends StringEditor {
74
76
 
75
77
  /* Ported from https://codemirror.net/addon/display/autorefresh.js */
76
78
  startListening (cm, state) {
77
- function check () {
79
+ const check = () => {
78
80
  if (cm.display.wrapper.offsetHeight) {
79
81
  this.stopListening(cm, state)
80
82
  if (cm.display.lastWrapHeight !== cm.display.wrapper.clientHeight) {
@@ -122,6 +122,8 @@ export class StarratingEditor extends StringEditor {
122
122
  }
123
123
 
124
124
  setValue (value) {
125
+ value = this.applyConstFilter(value)
126
+
125
127
  this.value = value
126
128
 
127
129
  for (let i = 0; i < this.radioGroup.length; i++) {
@@ -18,6 +18,8 @@ export class StringEditor extends AbstractEditor {
18
18
  }
19
19
 
20
20
  setValue (value, initial, fromTemplate) {
21
+ value = this.applyConstFilter(value)
22
+
21
23
  if (this.template && !fromTemplate) return
22
24
 
23
25
  if (!this.shouldBeUnset() && (value === null || typeof value === 'undefined')) value = ''
@@ -1,4 +1,4 @@
1
- import { ArrayEditor } from './array.js'
1
+ import { ArrayEditor, supportDragDrop } from './array.js'
2
2
  import { extend, generateUUID, trigger } from '../utilities.js'
3
3
 
4
4
  export class TableEditor extends ArrayEditor {
@@ -187,6 +187,8 @@ export class TableEditor extends ArrayEditor {
187
187
  }
188
188
 
189
189
  setValue (value = [], initial) {
190
+ value = this.applyConstFilter(value)
191
+
190
192
  /* Make sure value has between minItems and maxItems items in it */
191
193
  value = this.ensureArraySize(value)
192
194
 
@@ -221,7 +223,6 @@ export class TableEditor extends ArrayEditor {
221
223
  if (numrowsChanged || initial) this.refreshRowButtons()
222
224
 
223
225
  this.onChange()
224
-
225
226
  /* TODO: sortable */
226
227
  }
227
228
 
@@ -321,6 +322,8 @@ export class TableEditor extends ArrayEditor {
321
322
  this.rows[i].movedown_button = this._createMoveDownButton(i, controlsHolder)
322
323
  }
323
324
 
325
+ this._supportDragDrop(this.rows[i].row)
326
+
324
327
  if (typeof value !== 'undefined') this.rows[i].setValue(value)
325
328
 
326
329
  return this.rows[i]
@@ -434,6 +437,20 @@ export class TableEditor extends ArrayEditor {
434
437
  return button
435
438
  }
436
439
 
440
+ _supportDragDrop (tab) {
441
+ supportDragDrop(tab, (i, j) => {
442
+ const rows = this.getValue()
443
+ const tmp = rows[i]
444
+ rows.splice(i, 1)
445
+ rows.splice(j, 0, tmp)
446
+
447
+ this.setValue(rows)
448
+ this.onChange(true)
449
+
450
+ this.jsoneditor.trigger('moveRow', this.rows[j])
451
+ }, { useTrigger: true })
452
+ }
453
+
437
454
  addControls () {
438
455
  this.collapsed = false
439
456
  this.toggle_button = this._createToggleButton()