@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.
- package/package.json +56 -87
- package/src/compat/v2.js +120 -0
- package/src/compile/index.js +51 -0
- package/src/compile/v-jsf-compiled.vue.ejs +83 -0
- package/src/components/fragments/help-message.vue +48 -0
- package/src/components/fragments/node-slot.vue +49 -0
- package/src/components/fragments/section-header.vue +55 -0
- package/src/components/fragments/select-item-icon.vue +28 -0
- package/src/components/fragments/select-item.vue +43 -0
- package/src/components/fragments/select-selection.vue +35 -0
- package/src/components/fragments/text-field-menu.vue +68 -0
- package/src/components/node.vue +69 -0
- package/src/components/nodes/autocomplete.vue +95 -0
- package/src/components/nodes/checkbox.vue +27 -0
- package/src/components/nodes/color-picker.vue +43 -0
- package/src/components/nodes/combobox.vue +73 -0
- package/src/components/nodes/date-picker.vue +45 -0
- package/src/components/nodes/date-time-picker.vue +20 -0
- package/src/components/nodes/expansion-panels.vue +52 -0
- package/src/components/nodes/list.vue +112 -0
- package/src/components/nodes/markdown.vue +29 -0
- package/src/components/nodes/number-combobox.vue +73 -0
- package/src/components/nodes/number-field.vue +34 -0
- package/src/components/nodes/one-of-select.vue +56 -0
- package/src/components/nodes/section.vue +30 -0
- package/src/components/nodes/select.vue +79 -0
- package/src/components/nodes/slider.vue +34 -0
- package/src/components/nodes/switch.vue +29 -0
- package/src/components/nodes/tabs.vue +63 -0
- package/src/components/nodes/text-field.vue +29 -0
- package/src/components/nodes/textarea.vue +29 -0
- package/src/components/nodes/time-picker.vue +7 -0
- package/src/components/nodes/vertical-tabs.vue +70 -0
- package/src/components/options.js +25 -0
- package/src/components/tree.vue +26 -0
- package/src/components/types.ts +63 -0
- package/src/components/vjsf.vue +195 -0
- package/src/index.js +3 -0
- package/src/utils/clone.js +3 -0
- package/src/utils/dates.js +52 -0
- package/src/utils/props.js +87 -0
- package/src/utils/slots.js +19 -0
- package/types/compat/v2.d.ts +10 -0
- package/types/compat/v2.d.ts.map +1 -0
- package/types/compile/index.d.ts +7 -0
- package/types/compile/index.d.ts.map +1 -0
- package/types/components/fragments/help-message.vue.d.ts +8 -0
- package/types/components/fragments/help-message.vue.d.ts.map +1 -0
- package/types/components/fragments/node-slot.vue.d.ts +47 -0
- package/types/components/fragments/node-slot.vue.d.ts.map +1 -0
- package/types/components/fragments/section-header.vue.d.ts +8 -0
- package/types/components/fragments/section-header.vue.d.ts.map +1 -0
- package/types/components/fragments/select-item-icon.vue.d.ts +15 -0
- package/types/components/fragments/select-item-icon.vue.d.ts.map +1 -0
- package/types/components/fragments/select-item.vue.d.ts +12 -0
- package/types/components/fragments/select-item.vue.d.ts.map +1 -0
- package/types/components/fragments/select-selection.vue.d.ts +12 -0
- package/types/components/fragments/select-selection.vue.d.ts.map +1 -0
- package/types/components/fragments/text-field-menu.vue.d.ts +20 -0
- package/types/components/fragments/text-field-menu.vue.d.ts.map +1 -0
- package/types/components/node.vue.d.ts +10 -0
- package/types/components/node.vue.d.ts.map +1 -0
- package/types/components/nodes/autocomplete.vue.d.ts +27 -0
- package/types/components/nodes/autocomplete.vue.d.ts.map +1 -0
- package/types/components/nodes/checkbox.vue.d.ts +10 -0
- package/types/components/nodes/checkbox.vue.d.ts.map +1 -0
- package/types/components/nodes/color-picker.vue.d.ts +10 -0
- package/types/components/nodes/color-picker.vue.d.ts.map +1 -0
- package/types/components/nodes/combobox.vue.d.ts +27 -0
- package/types/components/nodes/combobox.vue.d.ts.map +1 -0
- package/types/components/nodes/date-picker.vue.d.ts +10 -0
- package/types/components/nodes/date-picker.vue.d.ts.map +1 -0
- package/types/components/nodes/date-time-picker.vue.d.ts +10 -0
- package/types/components/nodes/date-time-picker.vue.d.ts.map +1 -0
- package/types/components/nodes/expansion-panels.vue.d.ts +10 -0
- package/types/components/nodes/expansion-panels.vue.d.ts.map +1 -0
- package/types/components/nodes/list.vue.d.ts +10 -0
- package/types/components/nodes/list.vue.d.ts.map +1 -0
- package/types/components/nodes/markdown.vue.d.ts +27 -0
- package/types/components/nodes/markdown.vue.d.ts.map +1 -0
- package/types/components/nodes/number-combobox.vue.d.ts +27 -0
- package/types/components/nodes/number-combobox.vue.d.ts.map +1 -0
- package/types/components/nodes/number-field.vue.d.ts +27 -0
- package/types/components/nodes/number-field.vue.d.ts.map +1 -0
- package/types/components/nodes/one-of-select.vue.d.ts +10 -0
- package/types/components/nodes/one-of-select.vue.d.ts.map +1 -0
- package/types/components/nodes/section.vue.d.ts +10 -0
- package/types/components/nodes/section.vue.d.ts.map +1 -0
- package/types/components/nodes/select.vue.d.ts +27 -0
- package/types/components/nodes/select.vue.d.ts.map +1 -0
- package/types/components/nodes/slider.vue.d.ts +10 -0
- package/types/components/nodes/slider.vue.d.ts.map +1 -0
- package/types/components/nodes/switch.vue.d.ts +10 -0
- package/types/components/nodes/switch.vue.d.ts.map +1 -0
- package/types/components/nodes/tabs.vue.d.ts +10 -0
- package/types/components/nodes/tabs.vue.d.ts.map +1 -0
- package/types/components/nodes/text-field copy.vue.d.ts +10 -0
- package/types/components/nodes/text-field copy.vue.d.ts.map +1 -0
- package/types/components/nodes/text-field.vue.d.ts +27 -0
- package/types/components/nodes/text-field.vue.d.ts.map +1 -0
- package/types/components/nodes/textarea.vue.d.ts +27 -0
- package/types/components/nodes/textarea.vue.d.ts.map +1 -0
- package/types/components/nodes/time-picker.vue.d.ts +3 -0
- package/types/components/nodes/time-picker.vue.d.ts.map +1 -0
- package/types/components/nodes/vertical-tabs.vue.d.ts +10 -0
- package/types/components/nodes/vertical-tabs.vue.d.ts.map +1 -0
- package/types/components/options.d.ts +3 -0
- package/types/components/options.d.ts.map +1 -0
- package/types/components/tree.vue.d.ts +10 -0
- package/types/components/tree.vue.d.ts.map +1 -0
- package/types/components/types.d.ts +75 -0
- package/types/components/types.d.ts.map +1 -0
- package/types/components/v-jsf.vue.d.ts +13 -0
- package/types/components/v-jsf.vue.d.ts.map +1 -0
- package/types/components/vjsf.vue.d.ts +16 -0
- package/types/components/vjsf.vue.d.ts.map +1 -0
- package/types/index.d.ts +4 -0
- package/types/index.d.ts.map +1 -0
- package/types/utils/clone.d.ts +3 -0
- package/types/utils/clone.d.ts.map +1 -0
- package/types/utils/dates.d.ts +7 -0
- package/types/utils/dates.d.ts.map +1 -0
- package/types/utils/props.d.ts +21 -0
- package/types/utils/props.d.ts.map +1 -0
- package/types/utils/slots.d.ts +7 -0
- package/types/utils/slots.d.ts.map +1 -0
- package/.eslintignore +0 -9
- package/.eslintrc.js +0 -38
- package/.github/workflows/scrape-doc.yml +0 -14
- package/.nvmrc +0 -1
- package/CONTRIBUTE.md +0 -61
- package/FUNDING.yml +0 -1
- package/README.md +0 -19
- package/babel.config.js +0 -4
- package/dist/main.css +0 -67
- package/dist/main.js +0 -2
- package/dist/main.js.LICENSE.txt +0 -10
- package/dist/third-party.js +0 -8
- package/dist/third-party.js.LICENSE.txt +0 -8
- package/lib/VJsf.css +0 -67
- package/lib/VJsf.js +0 -117
- package/lib/VJsfNoDeps.js +0 -528
- package/lib/deps/third-party.js +0 -16
- package/lib/mixins/ColorProperty.js +0 -45
- package/lib/mixins/DateProperty.js +0 -170
- package/lib/mixins/Dependent.js +0 -69
- package/lib/mixins/EditableArray.js +0 -418
- package/lib/mixins/FileProperty.js +0 -81
- package/lib/mixins/MarkdownEditor.js +0 -183
- package/lib/mixins/ObjectContainer.js +0 -351
- package/lib/mixins/SelectProperty.js +0 -400
- package/lib/mixins/SimpleProperty.js +0 -165
- package/lib/mixins/Tooltip.js +0 -42
- package/lib/mixins/Validatable.js +0 -119
- package/lib/utils/expr-eval-parser.js +0 -47
- package/lib/utils/is-cyclic.js +0 -34
- package/lib/utils/json-refs.js +0 -209
- package/lib/utils/options.js +0 -328
- package/lib/utils/rules.js +0 -81
- package/lib/utils/schema.js +0 -100
- package/lib/utils/select.js +0 -141
- 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
|
-
}
|