@koumoul/vjsf 2.23.2 → 3.0.0-alpha.1

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 (162) hide show
  1. package/package.json +56 -87
  2. package/src/compat/v2.js +120 -0
  3. package/src/compile/index.js +51 -0
  4. package/src/compile/v-jsf-compiled.vue.ejs +83 -0
  5. package/src/components/fragments/help-message.vue +48 -0
  6. package/src/components/fragments/node-slot.vue +49 -0
  7. package/src/components/fragments/section-header.vue +55 -0
  8. package/src/components/fragments/select-item-icon.vue +28 -0
  9. package/src/components/fragments/select-item.vue +43 -0
  10. package/src/components/fragments/select-selection.vue +35 -0
  11. package/src/components/fragments/text-field-menu.vue +68 -0
  12. package/src/components/node.vue +69 -0
  13. package/src/components/nodes/autocomplete.vue +95 -0
  14. package/src/components/nodes/checkbox.vue +27 -0
  15. package/src/components/nodes/color-picker.vue +43 -0
  16. package/src/components/nodes/combobox.vue +73 -0
  17. package/src/components/nodes/date-picker.vue +45 -0
  18. package/src/components/nodes/date-time-picker.vue +20 -0
  19. package/src/components/nodes/expansion-panels.vue +52 -0
  20. package/src/components/nodes/list.vue +112 -0
  21. package/src/components/nodes/markdown.vue +29 -0
  22. package/src/components/nodes/number-combobox.vue +73 -0
  23. package/src/components/nodes/number-field.vue +34 -0
  24. package/src/components/nodes/one-of-select.vue +56 -0
  25. package/src/components/nodes/section.vue +30 -0
  26. package/src/components/nodes/select.vue +79 -0
  27. package/src/components/nodes/slider.vue +34 -0
  28. package/src/components/nodes/switch.vue +29 -0
  29. package/src/components/nodes/tabs.vue +63 -0
  30. package/src/components/nodes/text-field.vue +29 -0
  31. package/src/components/nodes/textarea.vue +29 -0
  32. package/src/components/nodes/time-picker.vue +7 -0
  33. package/src/components/nodes/vertical-tabs.vue +70 -0
  34. package/src/components/options.js +25 -0
  35. package/src/components/tree.vue +26 -0
  36. package/src/components/types.ts +63 -0
  37. package/src/components/vjsf.vue +195 -0
  38. package/src/index.js +3 -0
  39. package/src/utils/clone.js +3 -0
  40. package/src/utils/dates.js +52 -0
  41. package/src/utils/props.js +87 -0
  42. package/src/utils/slots.js +19 -0
  43. package/types/compat/v2.d.ts +10 -0
  44. package/types/compat/v2.d.ts.map +1 -0
  45. package/types/compile/index.d.ts +7 -0
  46. package/types/compile/index.d.ts.map +1 -0
  47. package/types/components/fragments/help-message.vue.d.ts +8 -0
  48. package/types/components/fragments/help-message.vue.d.ts.map +1 -0
  49. package/types/components/fragments/node-slot.vue.d.ts +47 -0
  50. package/types/components/fragments/node-slot.vue.d.ts.map +1 -0
  51. package/types/components/fragments/section-header.vue.d.ts +8 -0
  52. package/types/components/fragments/section-header.vue.d.ts.map +1 -0
  53. package/types/components/fragments/select-item-icon.vue.d.ts +15 -0
  54. package/types/components/fragments/select-item-icon.vue.d.ts.map +1 -0
  55. package/types/components/fragments/select-item.vue.d.ts +12 -0
  56. package/types/components/fragments/select-item.vue.d.ts.map +1 -0
  57. package/types/components/fragments/select-selection.vue.d.ts +12 -0
  58. package/types/components/fragments/select-selection.vue.d.ts.map +1 -0
  59. package/types/components/fragments/text-field-menu.vue.d.ts +20 -0
  60. package/types/components/fragments/text-field-menu.vue.d.ts.map +1 -0
  61. package/types/components/node.vue.d.ts +10 -0
  62. package/types/components/node.vue.d.ts.map +1 -0
  63. package/types/components/nodes/autocomplete.vue.d.ts +27 -0
  64. package/types/components/nodes/autocomplete.vue.d.ts.map +1 -0
  65. package/types/components/nodes/checkbox.vue.d.ts +10 -0
  66. package/types/components/nodes/checkbox.vue.d.ts.map +1 -0
  67. package/types/components/nodes/color-picker.vue.d.ts +10 -0
  68. package/types/components/nodes/color-picker.vue.d.ts.map +1 -0
  69. package/types/components/nodes/combobox.vue.d.ts +27 -0
  70. package/types/components/nodes/combobox.vue.d.ts.map +1 -0
  71. package/types/components/nodes/date-picker.vue.d.ts +10 -0
  72. package/types/components/nodes/date-picker.vue.d.ts.map +1 -0
  73. package/types/components/nodes/date-time-picker.vue.d.ts +10 -0
  74. package/types/components/nodes/date-time-picker.vue.d.ts.map +1 -0
  75. package/types/components/nodes/expansion-panels.vue.d.ts +10 -0
  76. package/types/components/nodes/expansion-panels.vue.d.ts.map +1 -0
  77. package/types/components/nodes/list.vue.d.ts +10 -0
  78. package/types/components/nodes/list.vue.d.ts.map +1 -0
  79. package/types/components/nodes/markdown.vue.d.ts +27 -0
  80. package/types/components/nodes/markdown.vue.d.ts.map +1 -0
  81. package/types/components/nodes/number-combobox.vue.d.ts +27 -0
  82. package/types/components/nodes/number-combobox.vue.d.ts.map +1 -0
  83. package/types/components/nodes/number-field.vue.d.ts +27 -0
  84. package/types/components/nodes/number-field.vue.d.ts.map +1 -0
  85. package/types/components/nodes/one-of-select.vue.d.ts +10 -0
  86. package/types/components/nodes/one-of-select.vue.d.ts.map +1 -0
  87. package/types/components/nodes/section.vue.d.ts +10 -0
  88. package/types/components/nodes/section.vue.d.ts.map +1 -0
  89. package/types/components/nodes/select.vue.d.ts +27 -0
  90. package/types/components/nodes/select.vue.d.ts.map +1 -0
  91. package/types/components/nodes/slider.vue.d.ts +10 -0
  92. package/types/components/nodes/slider.vue.d.ts.map +1 -0
  93. package/types/components/nodes/switch.vue.d.ts +10 -0
  94. package/types/components/nodes/switch.vue.d.ts.map +1 -0
  95. package/types/components/nodes/tabs.vue.d.ts +10 -0
  96. package/types/components/nodes/tabs.vue.d.ts.map +1 -0
  97. package/types/components/nodes/text-field copy.vue.d.ts +10 -0
  98. package/types/components/nodes/text-field copy.vue.d.ts.map +1 -0
  99. package/types/components/nodes/text-field.vue.d.ts +27 -0
  100. package/types/components/nodes/text-field.vue.d.ts.map +1 -0
  101. package/types/components/nodes/textarea.vue.d.ts +27 -0
  102. package/types/components/nodes/textarea.vue.d.ts.map +1 -0
  103. package/types/components/nodes/time-picker.vue.d.ts +3 -0
  104. package/types/components/nodes/time-picker.vue.d.ts.map +1 -0
  105. package/types/components/nodes/vertical-tabs.vue.d.ts +10 -0
  106. package/types/components/nodes/vertical-tabs.vue.d.ts.map +1 -0
  107. package/types/components/options.d.ts +3 -0
  108. package/types/components/options.d.ts.map +1 -0
  109. package/types/components/tree.vue.d.ts +10 -0
  110. package/types/components/tree.vue.d.ts.map +1 -0
  111. package/types/components/types.d.ts +75 -0
  112. package/types/components/types.d.ts.map +1 -0
  113. package/types/components/v-jsf.vue.d.ts +13 -0
  114. package/types/components/v-jsf.vue.d.ts.map +1 -0
  115. package/types/components/vjsf.vue.d.ts +16 -0
  116. package/types/components/vjsf.vue.d.ts.map +1 -0
  117. package/types/index.d.ts +4 -0
  118. package/types/index.d.ts.map +1 -0
  119. package/types/utils/clone.d.ts +3 -0
  120. package/types/utils/clone.d.ts.map +1 -0
  121. package/types/utils/dates.d.ts +7 -0
  122. package/types/utils/dates.d.ts.map +1 -0
  123. package/types/utils/props.d.ts +21 -0
  124. package/types/utils/props.d.ts.map +1 -0
  125. package/types/utils/slots.d.ts +7 -0
  126. package/types/utils/slots.d.ts.map +1 -0
  127. package/.eslintignore +0 -9
  128. package/.eslintrc.js +0 -38
  129. package/.github/workflows/scrape-doc.yml +0 -14
  130. package/.nvmrc +0 -1
  131. package/CONTRIBUTE.md +0 -61
  132. package/FUNDING.yml +0 -1
  133. package/README.md +0 -19
  134. package/babel.config.js +0 -4
  135. package/dist/main.css +0 -67
  136. package/dist/main.js +0 -2
  137. package/dist/main.js.LICENSE.txt +0 -10
  138. package/dist/third-party.js +0 -8
  139. package/dist/third-party.js.LICENSE.txt +0 -8
  140. package/lib/VJsf.css +0 -67
  141. package/lib/VJsf.js +0 -117
  142. package/lib/VJsfNoDeps.js +0 -528
  143. package/lib/deps/third-party.js +0 -16
  144. package/lib/mixins/ColorProperty.js +0 -45
  145. package/lib/mixins/DateProperty.js +0 -170
  146. package/lib/mixins/Dependent.js +0 -69
  147. package/lib/mixins/EditableArray.js +0 -418
  148. package/lib/mixins/FileProperty.js +0 -81
  149. package/lib/mixins/MarkdownEditor.js +0 -183
  150. package/lib/mixins/ObjectContainer.js +0 -351
  151. package/lib/mixins/SelectProperty.js +0 -400
  152. package/lib/mixins/SimpleProperty.js +0 -165
  153. package/lib/mixins/Tooltip.js +0 -42
  154. package/lib/mixins/Validatable.js +0 -119
  155. package/lib/utils/expr-eval-parser.js +0 -47
  156. package/lib/utils/is-cyclic.js +0 -34
  157. package/lib/utils/json-refs.js +0 -209
  158. package/lib/utils/options.js +0 -328
  159. package/lib/utils/rules.js +0 -81
  160. package/lib/utils/schema.js +0 -100
  161. package/lib/utils/select.js +0 -141
  162. package/webpack.config.js +0 -46
@@ -1,81 +0,0 @@
1
- const getFileDataUrl = (file) => {
2
- return new Promise(resolve => {
3
- const reader = new FileReader()
4
- reader.onload = () => resolve(reader.result)
5
- reader.readAsDataURL(file)
6
- })
7
- }
8
-
9
- const getFileResult = async (file, schema, filesAsDataUrl) => {
10
- let data = file
11
- if (schema.type === 'string' || (schema.properties && schema.properties.data && schema.properties.data.type === 'string')) {
12
- const dataUrl = await getFileDataUrl(file)
13
- data = filesAsDataUrl ? dataUrl : dataUrl.split(';base64,')[1]
14
- }
15
- if (schema.type === 'string') return data
16
- return {
17
- name: file.name,
18
- lastModified: new Date(file.lastModified).toISOString(),
19
- size: file.size,
20
- type: file.type,
21
- data
22
- }
23
- }
24
-
25
- export default {
26
- computed: {
27
- isFileProp() {
28
- if (!this.fullSchema) return
29
- if (this.fullSchema.type === 'string' &&
30
- (this.fullSchema.contentMediaType || this.display === 'file')) return true
31
- if (this.fullSchema.type === 'array' && this.fullSchema.items && this.fullSchema.items.type === 'string' &&
32
- (this.fullSchema.items.contentMediaType || this.display === 'file' || this.fullSchema.items['x-display'] === 'file')) return true
33
- if (this.fullSchema.type === 'object' &&
34
- (this.fullSchema.contentMediaType || this.display === 'file')) return true
35
- if (this.fullSchema.type === 'array' && this.fullSchema.items && this.fullSchema.items.type === 'object' &&
36
- (this.fullSchema.items.contentMediaType || this.display === 'file' || this.fullSchema.items['x-display'] === 'file')) return true
37
- return false
38
- }
39
- },
40
- watch: {
41
- isFileProp() {
42
- if (this.isFileProp && !this.fullSchema.writeOnly) {
43
- console.warn('File property should always be used with writeOnly attribute. Files are uploaded but not read in existing data.')
44
- }
45
- }
46
- },
47
- methods: {
48
- renderFileProp(h) {
49
- if (!this.isFileProp) return
50
- const props = { ...this.commonFieldProps, ...this.fullOptions.fileInputProps }
51
- delete props.value
52
- if (this.value && this.value.name) {
53
- props.placeholder = this.value.name
54
- props.persistentPlaceholder = true
55
- }
56
- const attrs = {}
57
- if (this.fullSchema.contentMediaType) attrs.accept = this.fullSchema.contentMediaType
58
- if (this.fullSchema.items && this.fullSchema.items.contentMediaType) attrs.accept = this.fullSchema.items.contentMediaType
59
- if (this.fullSchema.type === 'array') attrs.multiple = true
60
- const children = [...this.renderPropSlots(h)]
61
- const on = {
62
- change: async files => {
63
- if (this.fullSchema.type === 'array') {
64
- const contents = await Promise.all(files.map(file => getFileResult(file, this.fullSchema.items, this.fullOptions.filesAsDataUrl)))
65
- this.input(contents)
66
- this.change()
67
- } else {
68
- const content = await getFileResult(files, this.resolvedSchema, this.fullOptions.filesAsDataUrl)
69
- this.input(content)
70
- this.change()
71
- }
72
- }
73
- }
74
- if (this.htmlDescription) {
75
- children.push(this.renderTooltip(h, 'append-outer'))
76
- }
77
-
78
- return [h('v-file-input', { props, attrs, on, scopedSlots: this.$scopedSlots }, children)]
79
- }
80
- }
81
- }
@@ -1,183 +0,0 @@
1
- export default {
2
- computed: {
3
- isMarkdownProp() {
4
- if (!this.fullSchema) return
5
- return this.fullSchema['x-display'] === 'markdown'
6
- }
7
- },
8
- methods: {
9
- renderMarkdownProp(h) {
10
- if (!this.isMarkdownProp) return
11
-
12
- const children = [this.renderTooltip(h, 'append')]
13
-
14
- if (this.disabled) {
15
- children.push(h('v-card', { props: { flat: true }, class: 'px-0' }, [
16
- h('v-card-text', { domProps: { innerHTML: this.fullOptions.markdown(this.value) }, class: 'px-0 py-1' })
17
- ]))
18
- } else {
19
- children.push(h('v-card', { props: { outlined: true } }, [
20
- h('textarea', { attrs: { id: `${this.fullOptions.idPrefix}${this.dashKey}--easymde` } })
21
- ]))
22
- this.$nextTick(() => this.initEasyMDE())
23
- }
24
-
25
- return [h('v-input', {
26
- props: {
27
- value: this.value,
28
- name: this.fullKey,
29
- label: this.label,
30
- required: this.required,
31
- rules: this.rules,
32
- disabled: this.disabled,
33
- ...this.fullOptions.fieldProps
34
- },
35
- class: 'vjsf-markdown-input'
36
- }, children)]
37
- },
38
- initEasyMDE() {
39
- if (this.easymde) return
40
- if (!global.EasyMDE) {
41
- console.error('VJSF requires EasyMDE to be available to handle the markdown format.')
42
- return
43
- }
44
- const EasyMDE = global.EasyMDE
45
-
46
- const config = {
47
- element: this.$el.querySelector('textarea'),
48
- initialValue: this.value,
49
- renderingConfig: {},
50
- status: false,
51
- autoDownloadFontAwesome: false,
52
- spellChecker: false,
53
- minHeight: '300px',
54
- insertTexts: {
55
- link: [this.fullOptions.messages.mdeLink1, this.fullOptions.messages.mdeLink2],
56
- image: [this.fullOptions.messages.mdeImg1, this.fullOptions.messages.mdeImg2],
57
- table: [this.fullOptions.messages.mdeTable1, this.fullOptions.messages.mdeTable2],
58
- horizontalRule: ['', '\n\n-----\n\n']
59
- },
60
- // cf https://github.com/Ionaru/easy-markdown-editor/blob/master/src/js/easymde.js#L1380
61
- toolbar: [{
62
- name: 'bold',
63
- action: EasyMDE.toggleBold,
64
- className: 'mdi mdi-format-bold',
65
- title: this.fullOptions.messages.bold
66
- }, {
67
- name: 'italic',
68
- action: EasyMDE.toggleItalic,
69
- className: 'mdi mdi-format-italic',
70
- title: this.fullOptions.messages.italic
71
- }, {
72
- name: 'heading',
73
- action: EasyMDE.toggleHeadingSmaller,
74
- className: 'mdi mdi-format-title',
75
- title: this.fullOptions.messages.heading
76
- }, /* {
77
- name: 'heading-1',
78
- action: EasyMDE.toggleHeading1,
79
- className: 'mdi mdi-format-title',
80
- title: 'Titre 1'
81
- }, {
82
- name: 'heading-2',
83
- action: EasyMDE.toggleHeading2,
84
- className: 'mdi mdi-format-title',
85
- title: 'Titre 2'
86
- }, {
87
- name: 'heading-3',
88
- action: EasyMDE.toggleHeading3,
89
- className: 'mdi mdi-format-title',
90
- title: 'Titre 3'
91
- }, */
92
- '|',
93
- {
94
- name: 'quote',
95
- action: EasyMDE.toggleBlockquote,
96
- className: 'mdi mdi-format-quote-open',
97
- title: this.fullOptions.messages.quote
98
- },
99
- {
100
- name: 'unordered-list',
101
- action: EasyMDE.toggleUnorderedList,
102
- className: 'mdi mdi-format-list-bulleted',
103
- title: this.fullOptions.messages.unorderedList
104
- },
105
- {
106
- name: 'ordered-list',
107
- action: EasyMDE.toggleOrderedList,
108
- className: 'mdi mdi-format-list-numbered',
109
- title: this.fullOptions.messages.orderedList
110
- },
111
- '|',
112
- {
113
- name: 'link',
114
- action: EasyMDE.drawLink,
115
- className: 'mdi mdi-link',
116
- title: this.fullOptions.messages.createLink
117
- },
118
- {
119
- name: 'image',
120
- action: EasyMDE.drawImage,
121
- className: 'mdi mdi-image',
122
- title: this.fullOptions.messages.insertImage
123
- },
124
- {
125
- name: 'table',
126
- action: EasyMDE.drawTable,
127
- className: 'mdi mdi-table',
128
- title: this.fullOptions.messages.createTable
129
- },
130
- '|',
131
- {
132
- name: 'preview',
133
- action: EasyMDE.togglePreview,
134
- className: 'mdi mdi-eye accent--text',
135
- title: this.fullOptions.messages.preview,
136
- noDisable: true
137
- },
138
- '|',
139
- {
140
- name: 'undo',
141
- action: EasyMDE.undo,
142
- className: 'mdi mdi-undo',
143
- title: this.fullOptions.messages.undo,
144
- noDisable: true
145
- },
146
- {
147
- name: 'redo',
148
- action: EasyMDE.redo,
149
- className: 'mdi mdi-redo',
150
- title: this.fullOptions.messages.redo,
151
- noDisable: true
152
- },
153
- '|',
154
- {
155
- name: 'guide',
156
- action: 'https://simplemde.com/markdown-guide',
157
- className: 'mdi mdi-help-circle success--text',
158
- title: this.fullOptions.messages.mdeGuide,
159
- noDisable: true
160
- }
161
- ],
162
- ...this.fullOptions.easyMDEOptions
163
- }
164
- this.easymde = new EasyMDE(config)
165
-
166
- let changed = false
167
- this.easymde.codemirror.on('change', () => {
168
- changed = true
169
- this.input(this.easymde.value())
170
- })
171
- this.easymde.codemirror.on('blur', () => {
172
- // timeout to prevent triggering save when clicking on a menu button
173
- this.blurTimeout = setTimeout(() => {
174
- if (changed) this.change()
175
- changed = false
176
- }, 500)
177
- })
178
- this.easymde.codemirror.on('focus', () => {
179
- clearTimeout(this.blurTimeout)
180
- })
181
- }
182
- }
183
- }
@@ -1,351 +0,0 @@
1
- import copy from 'fast-copy'
2
-
3
- export default {
4
- data() {
5
- return {
6
- currentOneOf: null,
7
- currentTab: null,
8
- showCurrentOneOf: true,
9
- subModels: {}, // a container for objects from root subSchemass and allOfs
10
- currentStep: 1,
11
- steps: []
12
- }
13
- },
14
- computed: {
15
- isObjectContainer() {
16
- if (!this.fullSchema) return
17
- if (this.fullSchema.type !== 'object' && !Array.isArray(this.fullSchema.items)) return false
18
- if (this.isSelectProp) return false
19
- if (this.isFileProp) return false
20
- return true
21
- },
22
- subSchemas() {
23
- if (!this.fullSchema) return
24
- return this.fullSchema.oneOf || this.fullSchema.anyOf
25
- },
26
- subSchemasConstProp() {
27
- if (!this.subSchemas) return
28
- const props = this.subSchemas[0].properties
29
- const key = Object.keys(props).find(p => !!props[p].const)
30
- if (!key) return
31
- return { ...props[key], key, htmlDescription: this.fullOptions.memMarkdown(props[key].description) }
32
- },
33
- subSchemasRequired() {
34
- if (!this.subSchemas || !this.subSchemasConstProp) return false
35
- if (this.fullSchema.oneOf) return true
36
- if (this.fullSchema.anyOf && this.fullSchema.required && this.fullSchema.required.find(r => r === this.oneOfConstProp.key)) return true
37
- },
38
- subSchemasRules() {
39
- if (!this.fullSchema) return
40
- const rules = []
41
- if (this.subSchemasRequired) rules.push((val) => (val !== undefined && val !== null && val !== '') || this.fullOptions.messages.required)
42
- return rules
43
- }
44
- },
45
- watch: {
46
- currentOneOf(newVal, oldVal) {
47
- // use this boolean to force removing then re-creating the object property
48
- // based on the currentOneOf sub schema. If we don't the component is reused and reactivity creates some difficult bugs.
49
- this.showCurrentOneOf = false
50
- this.$nextTick(() => {
51
- this.showCurrentOneOf = true
52
- if (!this.currentOneOf) this.$set(this.subModels, 'currentOneOf', {})
53
- else this.input(this.fixProperties(this.value), false, false)
54
- if (this.triggerChangeCurrentOneOf) {
55
- this.$nextTick(() => {
56
- this.triggerChangeCurrentOneOf = false
57
- this.change()
58
- })
59
- }
60
- })
61
- },
62
- subModels: {
63
- handler() {
64
- this.input(this.fixProperties(this.value), false, false)
65
- },
66
- deep: true
67
- }
68
- },
69
- methods: {
70
- isSection(prop, insideAllOf) {
71
- if (!prop) return false
72
- if (!prop.title) return false
73
- if (prop['x-fromUrl'] || prop['x-fromData'] || prop['contentMediaType'] || prop['x-display'] === 'file') return false
74
- if (prop.allOf) return true
75
- if (insideAllOf && (prop.anyOf || prop.oneOf)) return true
76
- if (prop.properties || Array.isArray(prop.items)) return true
77
- return false
78
- },
79
- initObjectContainer(model) {
80
- if (this.fullSchema.type !== 'object') return
81
-
82
- // Init subModels for allOf subschemas
83
- if (this.fullSchema.allOf) {
84
- this.fullSchema.allOf.forEach((allOf, i) => {
85
- this.$set(this.subModels, 'allOf-' + i, copy(model))
86
- })
87
- }
88
-
89
- // Case of a sub type selection based on a subSchemas
90
- this.currentOneOf = null
91
- if (this.subSchemas && !this.currentOneOf && this.subSchemasConstProp) {
92
- if (model && model[this.subSchemasConstProp.key]) {
93
- this.currentOneOf = this.subSchemas.find(item => item.properties[this.subSchemasConstProp.key].const === model[this.subSchemasConstProp.key])
94
- } else if (this.fullSchema.default) {
95
- this.currentOneOf = this.subSchemas.find(item => item.properties[this.subSchemasConstProp.key].const === this.fullSchema.default[this.subSchemasConstProp.key])
96
- }
97
- }
98
-
99
- // Init subModel for current subSchemas
100
- if (this.currentOneOf) {
101
- this.$set(this.subModels, 'currentOneOf', copy(model))
102
- } else {
103
- this.$set(this.subModels, 'currentOneOf', {})
104
- }
105
- },
106
- renderStepperStep(h, schema, subModelKey, childProp, step, isLast) {
107
- if (!childProp) return
108
- const modelKey = subModelKey || schema.key
109
- const hasError = this.dedupChildrenWithValidatedErrors.includes(modelKey)
110
- const props = {
111
- step,
112
- editable: step < this.currentStep,
113
- complete: step < this.currentStep,
114
- rules: [() => !hasError]
115
- }
116
- return [h('v-stepper-step', { props }, [schema.title]), isLast ? null : h('v-divider')]
117
- },
118
- renderSection(h, schema, subModelKey, childProp, step, isLast) {
119
- if (!childProp) return
120
- const modelKey = subModelKey || schema.key
121
- const key = 'section-' + modelKey
122
-
123
- if (schema['x-display'] === 'hidden' || (schema.readOnly && this.fullOptions.hideReadOnly)) {
124
- return [childProp]
125
- }
126
- if (this.display === 'expansion-panels') {
127
- return [h('v-expansion-panel', { key }, [
128
- h('v-expansion-panel-header', { class: { 'error--text': this.dedupChildrenWithValidatedErrors.includes(modelKey) } }, [schema.title]),
129
- h('v-expansion-panel-content', { props: { eager: true } }, [childProp])
130
- ])]
131
- } else if (this.display === 'tabs') {
132
- return [
133
- h('v-tab', { key, props: { href: `#tab-${this.fullOptions.idPrefix}${this.dashKey}-${modelKey}` } }, [
134
- h('span', { class: { 'error--text': this.dedupChildrenWithValidatedErrors.includes(modelKey) } }, [schema.title])
135
- ]),
136
- h('v-tab-item',
137
- { key, props: { value: `tab-${this.fullOptions.idPrefix}${this.dashKey}-${modelKey}`, eager: true } },
138
- [h('v-card', { props: { tile: true, flat: true } }, [h('v-card-text', [childProp])])]
139
- )
140
- ]
141
- } else if (this.display === 'stepper' || this.display === 'vertical-stepper') {
142
- return [
143
- h('v-stepper-content',
144
- { key, props: { step, eager: true } },
145
- [h('v-card', { props: { tile: true, flat: true } }, [
146
- h('v-card-text', { class: { 'pa-0': true } }, [childProp]),
147
- isLast ? null : h('v-card-actions', { class: { 'px-0': true } }, [h('v-btn', { props: { color: 'primary' },
148
- on: { click: () => {
149
- if (childProp.componentInstance.validate(true)) {
150
- this.currentStep += 1
151
- }
152
- } } }, this.fullOptions.messages.stepperContinue)])
153
- ])]
154
- )
155
- ]
156
- }
157
- },
158
- renderChildProp(h, schema, subModelKey, sectionDepth, forceRequired, showSectionTitle) {
159
- this.objectContainerChildrenCount += 1
160
- let wrapper
161
- if (subModelKey) wrapper = this.subModels
162
- else if (Array.isArray(this.value)) wrapper = [...this.value]
163
- else wrapper = { ...this.value }
164
-
165
- const modelKey = subModelKey || schema.key
166
-
167
- // Manage default values
168
- let value = wrapper[modelKey]
169
- value = this.fixValueType(value, schema)
170
- if (value === undefined) {
171
- value = this.defaultValue(schema)
172
- if (schema.default !== undefined) value = copy(schema.default)
173
- if (value !== undefined && value !== null) {
174
- this.$set(wrapper, modelKey, value)
175
- if (!subModelKey) this.input(wrapper, false, false)
176
- }
177
- }
178
- return h('v-jsf', {
179
- props: {
180
- schema: { readOnly: this.fullSchema.readOnly, ...schema },
181
- value,
182
- modelRoot: this.modelRoot || this.value,
183
- modelKey,
184
- parentKey: `${this.fullKey}.`,
185
- required: forceRequired || !!(this.fullSchema.required && this.fullSchema.required.includes(schema.key)),
186
- options: { ...this.fullOptions, autofocus: this.fullOptions.autofocus && this.objectContainerChildrenCount === 1 },
187
- optionsRoot: this.initialOptions,
188
- sectionDepth,
189
- sharedData: this.sharedData,
190
- showSectionTitle
191
- },
192
- class: this.fullOptions.childrenClass,
193
- scopedSlots: this.childScopedSlots(modelKey),
194
- key: modelKey,
195
- on: {
196
- error: e => this.$emit('error', e),
197
- input: v => {
198
- if (v === undefined) {
199
- // set empty value instead of deleting key in the special case of the parts
200
- // of a tuple (except the last part), otherwise we move last parts of the array to the beginning of the array
201
- if (Array.isArray(wrapper) && parseInt(modelKey) < (wrapper.length - 1)) {
202
- this.$set(wrapper, modelKey, v)
203
- } else {
204
- this.$delete(wrapper, modelKey)
205
- }
206
- } else {
207
- this.$set(wrapper, modelKey, v)
208
- }
209
- if (!subModelKey) this.input(wrapper, false, false)
210
- },
211
- change: v => this.change(false)
212
- }
213
- }, this.childSlots(h, schema.key))
214
- },
215
- renderObjectContainer(h) {
216
- if (!this.isObjectContainer) return
217
- if ([undefined, null].includes(this.value)) return []
218
-
219
- const flatChildren = []
220
- this.objectContainerChildrenCount = 0
221
- const sections = []
222
- if (this.fullSchema.properties) {
223
- this.fullSchema.properties.forEach((schema) => {
224
- if (this.isSection(schema)) {
225
- sections.push({ schema, subModelKey: null, forceRequired: false })
226
- } else {
227
- flatChildren.push(this.renderChildProp(h, schema, null, this.sectionDepth, false, false))
228
- }
229
- })
230
- }
231
- if (Array.isArray(this.fullSchema.items)) {
232
- this.fullSchema.items.forEach((schema, i) => {
233
- const forceRequired = this.value.length > i || (this.fullSchema.minItems && this.fullSchema.minItems > i)
234
- if (this.isSection(schema)) {
235
- sections.push({ schema, subModelKey: null, forceRequired })
236
- } else {
237
- flatChildren.push(this.renderChildProp(h, schema, null, this.sectionDepth, forceRequired, false))
238
- }
239
- })
240
- }
241
- if (this.fullSchema.allOf) {
242
- this.fullSchema.allOf.forEach((allOf, i) => {
243
- const schema = { ...allOf, type: 'object', key: '' + i }
244
- if (this.isSection(allOf, true)) {
245
- sections.push({ schema, subModelKey: 'allOf-' + i, forceRequired: false })
246
- } else {
247
- flatChildren.push(this.renderChildProp(h, schema, 'allOf-' + i, this.sectionDepth, false, false))
248
- }
249
- })
250
- }
251
-
252
- let sectionsChildren = []
253
- let stepperSteps = []
254
- sections.forEach((section, i) => {
255
- const isSimpleSection = !['expansion-panels', 'tabs', 'stepper', 'vertical-stepper'].includes(this.display)
256
- const childProp = this.renderChildProp(h, section.schema, section.subModelKey, this.sectionDepth + 1, section.forceRequired, isSimpleSection)
257
- if (isSimpleSection) sectionsChildren.push(childProp)
258
- else sectionsChildren = sectionsChildren.concat(this.renderSection(h, section.schema, section.subModelKey, childProp, i + 1, i === sections.length - 1))
259
- if (this.display === 'stepper' || this.display === 'vertical-stepper') stepperSteps = stepperSteps.concat(this.renderStepperStep(h, section.schema, section.subModelKey, childProp, i + 1, i === sections.length - 1))
260
- })
261
-
262
- if (this.display === 'expansion-panels' && sectionsChildren.length) {
263
- const props = { ...this.fullOptions.expansionPanelsProps, ...this.fullSchema['x-props'] }
264
- sectionsChildren = [h('v-expansion-panels', { props }, sectionsChildren)]
265
- }
266
- if (this.display === 'tabs' && sectionsChildren.length) {
267
- const props = { ...this.fullOptions.tabsProps, ...this.fullSchema['x-props'] }
268
- if (this.currentTab && this.dedupChildrenWithValidatedErrors.includes(this.currentTab)) {
269
- props.sliderColor = 'error'
270
- }
271
- sectionsChildren = [h('v-tabs', { props, on: { change: value => { this.currentTab = value.split('-').pop() } } }, sectionsChildren)]
272
- }
273
- if (this.display === 'stepper' && sectionsChildren.length) {
274
- const props = { ...this.fullOptions.stepperProps, ...this.fullSchema['x-props'], value: this.currentStep }
275
- sectionsChildren = [h('v-stepper', { props, style: 'width: 100%;', on: { change: value => { this.currentStep = value } } }, [
276
- h('v-stepper-header', {}, stepperSteps),
277
- h('v-stepper-items', {}, sectionsChildren)
278
- ])]
279
- }
280
- if (this.display === 'vertical-stepper' && sectionsChildren.length) {
281
- const props = { ...this.fullOptions.verticalStepperProps, ...this.fullSchema['x-props'], vertical: true, value: this.currentStep }
282
- const stepperChildren = []
283
- for (let i = 0; i < sectionsChildren.length; i++) {
284
- stepperChildren.push(stepperSteps[i * 2])
285
- stepperChildren.push(sectionsChildren[i])
286
- }
287
- sectionsChildren = [h('v-stepper', { props, style: 'width: 100%;', on: { change: value => { this.currentStep = value } } }, stepperChildren)]
288
- }
289
-
290
- if (this.subSchemas && this.subSchemas.length) {
291
- const props = {
292
- ...this.commonFieldProps,
293
- ...((this.subSchemasConstProp && this.subSchemasConstProp['x-props']) || {}),
294
- disabled: this.disabled || (this.subSchemasConstProp && this.subSchemasConstProp.readOnly),
295
- value: this.currentOneOf,
296
- label: (this.subSchemasConstProp && this.subSchemasConstProp.title) || this.fullSchema.title,
297
- items: this.subSchemas
298
- .filter(item => !item['x-if'] || !!this.getFromExpr(item['x-if']))
299
- .filter(item => item.properties && item.properties[this.subSchemasConstProp.key]),
300
- required: this.subSchemasRequired,
301
- clearable: !this.subSchemasRequired,
302
- itemValue: item => item.properties[this.subSchemasConstProp.key].const,
303
- itemText: item => item.title || item.properties[this.subSchemasConstProp.key].const,
304
- rules: this.subSchemasRules,
305
- returnObject: true
306
- }
307
- const on = {
308
- input: value => {
309
- this.currentOneOf = value
310
- this.triggerChangeCurrentOneOf = true
311
- }
312
- }
313
- flatChildren.push(h('v-select', { props, on, style: (this.subSchemasConstProp && this.subSchemasConstProp['x-style']) || '' }, [this.renderTooltip(h, 'append-outer')]))
314
- if (this.currentOneOf && this.showCurrentOneOf) {
315
- flatChildren.push(this.renderChildProp(h, { ...this.currentOneOf, type: 'object', title: null }, 'currentOneOf', this.sectionDepth + 1))
316
- }
317
- }
318
- return [h('v-row', { class: `ma-0 ${this.fullOptions.objectContainerClass}` }, [
319
- (this.showSectionTitle && h('v-col', { props: { cols: 12 }, class: 'pa-0' }, [h('span', {
320
- class: 'py-2 ' + (this.fullOptions.sectionsTitlesClasses[this.sectionDepth - 1] || this.fullOptions.sectionsTitlesClasses[this.fullOptions.sectionsTitlesClasses.length - 1])
321
- }, [`${this.fullSchema.title}\xa0`])])),
322
- // display a local error only we don't already have an error displayed in the children
323
- (this.localRuleError && !this.dedupChildrenWithValidatedErrors.length) && h('v-col', { props: { cols: 12 }, class: { 'px-0': true, 'error--text': true } }, this.localRuleError),
324
- // display the description as block of text on top of section
325
- this.fullSchema.description && !this.subSchemasConstProp && h('v-col', { props: { cols: 12 }, class: { 'pa-0': true }, domProps: { innerHTML: this.htmlDescription } })]
326
- .concat(flatChildren).concat(sectionsChildren))
327
- ]
328
- },
329
- // pass an extract of $slots from current container to a child by matching then removing the prefix
330
- childSlots(h, childKey) {
331
- return Object.keys(this.$slots)
332
- .filter(slot => slot.startsWith(`${childKey}.`) || slot.startsWith(`${childKey}-`))
333
- .map(slot => {
334
- const childSlot = slot.startsWith(`${childKey}.`) ? slot.replace(`${childKey}.`, '') : slot.replace(`${childKey}-`, '')
335
- return h('template', { slot: childSlot }, this.$slots[slot])
336
- })
337
- },
338
- childScopedSlots(childKey) {
339
- return Object.keys(this.$scopedSlots)
340
- .filter(slot => slot.startsWith('custom-') || slot.startsWith(`${childKey}.`) || slot.startsWith(`${childKey}-`) || slot === childKey)
341
- .reduce((a, slot) => {
342
- let childSlot = 'default'
343
- if (slot.startsWith(`${childKey}.`)) childSlot = slot.replace(`${childKey}.`, '')
344
- if (slot.startsWith(`${childKey}-`)) childSlot = slot.replace(`${childKey}-`, '')
345
- if (slot.startsWith(`custom-`)) childSlot = slot
346
- a[childSlot] = this.$scopedSlots[slot]
347
- return a
348
- }, {})
349
- }
350
- }
351
- }