@koumoul/vjsf 2.12.0-beta.8 → 2.12.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/dist/main.js +1 -1
- package/lib/VJsf.js +8 -0
- package/lib/VJsfNoDeps.js +3 -2
- package/lib/mixins/EditableArray.js +133 -34
- package/lib/mixins/ObjectContainer.js +2 -2
- package/lib/mixins/SelectProperty.js +4 -0
- package/lib/utils/options.js +35 -8
- package/package.json +1 -1
- package/test-apps/compiled/README.me +0 -10
- package/test-apps/compiled/index.html +0 -85
- package/test-apps/compiled/package-lock.json +0 -37386
- package/test-apps/compiled/package.json +0 -7
package/lib/VJsf.js
CHANGED
|
@@ -28,8 +28,12 @@ import {
|
|
|
28
28
|
VIcon,
|
|
29
29
|
VInput,
|
|
30
30
|
VRow,
|
|
31
|
+
VList,
|
|
32
|
+
VListItem,
|
|
31
33
|
VListItemContent,
|
|
34
|
+
VListItemIcon,
|
|
32
35
|
VListItemTitle,
|
|
36
|
+
VListItemAction,
|
|
33
37
|
VMenu,
|
|
34
38
|
VRadio,
|
|
35
39
|
VRadioGroup,
|
|
@@ -80,8 +84,12 @@ export default {
|
|
|
80
84
|
VIcon,
|
|
81
85
|
VInput,
|
|
82
86
|
VRow,
|
|
87
|
+
VList,
|
|
88
|
+
VListItem,
|
|
83
89
|
VListItemContent,
|
|
90
|
+
VListItemIcon,
|
|
84
91
|
VListItemTitle,
|
|
92
|
+
VListItemAction,
|
|
85
93
|
VMenu,
|
|
86
94
|
VRadio,
|
|
87
95
|
VRadioGroup,
|
package/lib/VJsfNoDeps.js
CHANGED
|
@@ -50,7 +50,8 @@ export default {
|
|
|
50
50
|
modelKey: { type: [String, Number], default: 'root' },
|
|
51
51
|
parentKey: { type: String, default: '' },
|
|
52
52
|
required: { type: Boolean, default: false },
|
|
53
|
-
sectionDepth: { type: Number, default: 0 }
|
|
53
|
+
sectionDepth: { type: Number, default: 0 },
|
|
54
|
+
sharedData: { type: Object, default: () => ({}) }
|
|
54
55
|
},
|
|
55
56
|
data() {
|
|
56
57
|
return {
|
|
@@ -395,7 +396,7 @@ export default {
|
|
|
395
396
|
},
|
|
396
397
|
input(value, initial = false, fastForward = true) {
|
|
397
398
|
if (Array.isArray(value) && this.separator) value = value.join(this.separator)
|
|
398
|
-
if (value === null || value === undefined
|
|
399
|
+
if (value === null || value === undefined) {
|
|
399
400
|
if (this.fullSchema.nullable) {
|
|
400
401
|
if (this.value !== null) {
|
|
401
402
|
this.changed = true
|
|
@@ -105,7 +105,8 @@ export default {
|
|
|
105
105
|
options: { ...this.fullOptions, hideReadOnly: false },
|
|
106
106
|
optionsRoot: this.initialOptions,
|
|
107
107
|
sectionDepth: this.sectionDepth + 1,
|
|
108
|
-
separateValidation: false
|
|
108
|
+
separateValidation: false,
|
|
109
|
+
sharedData: this.sharedData
|
|
109
110
|
},
|
|
110
111
|
ref: modelKey,
|
|
111
112
|
scopedSlots: this.childScopedSlots(this.fullSchema.key)
|
|
@@ -173,7 +174,8 @@ export default {
|
|
|
173
174
|
options,
|
|
174
175
|
optionsRoot: this.initialOptions,
|
|
175
176
|
sectionDepth: this.sectionDepth + 1,
|
|
176
|
-
separateValidation: this.fullOptions.editMode !== 'inline'
|
|
177
|
+
separateValidation: this.fullOptions.editMode !== 'inline',
|
|
178
|
+
sharedData: this.sharedData
|
|
177
179
|
},
|
|
178
180
|
scopedSlots: this.childScopedSlots(this.fullSchema.key),
|
|
179
181
|
ref: 'item-' + i,
|
|
@@ -195,6 +197,110 @@ export default {
|
|
|
195
197
|
}
|
|
196
198
|
}, this.childSlots(h, this.fullSchema.key))
|
|
197
199
|
},
|
|
200
|
+
renderArrayItemMenu(h, item, header, isCurrentInlineEdit) {
|
|
201
|
+
if (this.disabled || this.fromUrl || this.fullSchema.fromData) return
|
|
202
|
+
const menuItems = []
|
|
203
|
+
|
|
204
|
+
for (const operation of this.fullOptions.arrayOperations) {
|
|
205
|
+
if (operation === 'duplicate') {
|
|
206
|
+
menuItems.push({
|
|
207
|
+
title: this.fullOptions.messages.duplicate,
|
|
208
|
+
color: 'default',
|
|
209
|
+
icon: this.fullOptions.icons.duplicate,
|
|
210
|
+
disabled: false,
|
|
211
|
+
on: { click: () => {
|
|
212
|
+
const index = this.value.findIndex(i => i === item)
|
|
213
|
+
const value = [...this.value]
|
|
214
|
+
value.splice(index, 0, { ...item })
|
|
215
|
+
this.input(value)
|
|
216
|
+
this.change()
|
|
217
|
+
this.shouldValidate = true
|
|
218
|
+
header.componentInstance.validate()
|
|
219
|
+
} }
|
|
220
|
+
})
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (operation === 'delete') {
|
|
224
|
+
menuItems.push({
|
|
225
|
+
title: this.fullOptions.messages.delete,
|
|
226
|
+
color: 'warning',
|
|
227
|
+
icon: this.fullOptions.icons.delete,
|
|
228
|
+
disabled: isCurrentInlineEdit,
|
|
229
|
+
on: { click: () => {
|
|
230
|
+
const value = this.value.filter(i => i !== item)
|
|
231
|
+
this.input(value)
|
|
232
|
+
this.change()
|
|
233
|
+
this.shouldValidate = true
|
|
234
|
+
header.componentInstance.validate()
|
|
235
|
+
} }
|
|
236
|
+
})
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (operation === 'copy' && this.fullSchema['x-arrayGroup']) {
|
|
240
|
+
menuItems.push({
|
|
241
|
+
title: this.fullOptions.messages.copy,
|
|
242
|
+
color: 'default',
|
|
243
|
+
icon: this.fullOptions.icons.copy,
|
|
244
|
+
disabled: false,
|
|
245
|
+
on: { click: () => {
|
|
246
|
+
this.$set(this.sharedData, 'clipboard_' + this.fullSchema['x-arrayGroup'], item)
|
|
247
|
+
} }
|
|
248
|
+
})
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (operation === 'paste' && this.fullSchema['x-arrayGroup']) {
|
|
252
|
+
menuItems.push({
|
|
253
|
+
title: this.fullOptions.messages.paste,
|
|
254
|
+
color: 'primary',
|
|
255
|
+
icon: this.fullOptions.icons.paste,
|
|
256
|
+
disabled: !(this.sharedData['clipboard_' + this.fullSchema['x-arrayGroup']]),
|
|
257
|
+
on: { click: () => {
|
|
258
|
+
if (this.fullOptions.editMode === 'inline') {
|
|
259
|
+
this.editabledArrayProp.editItem = null
|
|
260
|
+
this.editabledArrayProp.currentDialog = null
|
|
261
|
+
}
|
|
262
|
+
const index = this.value.findIndex(i => i === item)
|
|
263
|
+
const value = [...this.value]
|
|
264
|
+
value[index] = this.sharedData['clipboard_' + this.fullSchema['x-arrayGroup']]
|
|
265
|
+
this.input(value)
|
|
266
|
+
this.change()
|
|
267
|
+
this.shouldValidate = true
|
|
268
|
+
header.componentInstance.validate()
|
|
269
|
+
} }
|
|
270
|
+
})
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (!menuItems.length) return
|
|
275
|
+
|
|
276
|
+
// if there is only one item, do not create a menu but instead a single button
|
|
277
|
+
if (menuItems.length === 1) {
|
|
278
|
+
return h('v-btn', {
|
|
279
|
+
props: { icon: true, disabled: menuItems[0].disabled },
|
|
280
|
+
on: menuItems[0].on,
|
|
281
|
+
attrs: { title: menuItems[0].title },
|
|
282
|
+
class: 'ml-1'
|
|
283
|
+
}, [h('v-icon', { props: { color: menuItems[0].color } }, [menuItems[0].icon])])
|
|
284
|
+
}
|
|
285
|
+
return h('v-menu', {
|
|
286
|
+
props: { offsetY: true, left: true },
|
|
287
|
+
scopedSlots: {
|
|
288
|
+
activator: ({ on }) => h('v-btn', {
|
|
289
|
+
props: { icon: true },
|
|
290
|
+
attrs: { title: this.fullOptions.messages.openMenu },
|
|
291
|
+
class: 'ml-1',
|
|
292
|
+
on
|
|
293
|
+
}, [h('v-icon', this.fullOptions.icons.arrayMenu)]),
|
|
294
|
+
default: () => h('v-list', { class: 'pa-0', props: { dense: true } }, menuItems.map(menuItem => h('v-list-item', {
|
|
295
|
+
on: menuItem.on,
|
|
296
|
+
props: { disabled: menuItem.disabled }
|
|
297
|
+
}, [
|
|
298
|
+
h('v-list-item-icon', { class: 'mr-2' }, [h('v-icon', { props: { color: menuItem.color, small: true } }, [menuItem.icon])]),
|
|
299
|
+
h('v-list-item-content', {}, [h('v-list-item-title', {}, [menuItem.title])])
|
|
300
|
+
])))
|
|
301
|
+
}
|
|
302
|
+
})
|
|
303
|
+
},
|
|
198
304
|
renderEditableArray(h) {
|
|
199
305
|
if (!this.isEditableArray) return
|
|
200
306
|
const headerChildren = []
|
|
@@ -207,13 +313,15 @@ export default {
|
|
|
207
313
|
}
|
|
208
314
|
}
|
|
209
315
|
const header = h('v-input', {
|
|
210
|
-
class: 'mt-2 pr-1 vjsf-array-header',
|
|
316
|
+
class: 'mt-2 mb-3 pr-1 vjsf-array-header',
|
|
211
317
|
props: { label: this.label, rules: this.rules, value: this.value, validateOnBlur: !this.shouldValidate, hideDetails: 'auto' }
|
|
212
318
|
}, headerChildren)
|
|
213
319
|
|
|
214
|
-
|
|
320
|
+
const sortable = !this.fullOptions.disableSorting && !this.fullSchema.readOnly
|
|
321
|
+
|
|
322
|
+
let listItems
|
|
215
323
|
if (this.value && this.value.length) {
|
|
216
|
-
|
|
324
|
+
listItems = this.value.filter(item => !!item).map((item, i) => {
|
|
217
325
|
let editAction
|
|
218
326
|
const isCurrentInlineEdit = this.fullOptions.editMode === 'inline' && this.editabledArrayProp.currentDialog === i
|
|
219
327
|
if (!this.disabled && this.fullOptions.arrayOperations.includes('update')) {
|
|
@@ -224,20 +332,7 @@ export default {
|
|
|
224
332
|
}
|
|
225
333
|
}
|
|
226
334
|
|
|
227
|
-
|
|
228
|
-
if (!this.disabled && !this.fromUrl && !this.fullSchema.fromData && this.fullOptions.arrayOperations.includes('delete')) {
|
|
229
|
-
deleteAction = h('v-btn', { props: { icon: true, color: 'warning', disabled: isCurrentInlineEdit },
|
|
230
|
-
attrs: { id: this.fullOptions.idPrefix + this.dashKey + '-' + i + '--delete-button' },
|
|
231
|
-
class: { 'vjsf-array-delete-button': true },
|
|
232
|
-
on: { click: () => {
|
|
233
|
-
const value = this.value.filter(i => i !== item)
|
|
234
|
-
this.input(value)
|
|
235
|
-
this.change()
|
|
236
|
-
this.shouldValidate = true
|
|
237
|
-
header.componentInstance.validate()
|
|
238
|
-
} } }, [h('v-icon', this.fullOptions.icons.delete)])
|
|
239
|
-
}
|
|
240
|
-
const actions = h('v-card-actions', { class: 'pa-0' }, [h('v-spacer'), editAction, deleteAction])
|
|
335
|
+
const actions = h('v-card-actions', { class: 'pa-0' }, [h('v-spacer'), editAction, this.renderArrayItemMenu(h, item, header, isCurrentInlineEdit)])
|
|
241
336
|
|
|
242
337
|
let itemChild, cardStyle, itemKey
|
|
243
338
|
if (isCurrentInlineEdit) {
|
|
@@ -245,12 +340,8 @@ export default {
|
|
|
245
340
|
itemKey = 'item-edit-' + i
|
|
246
341
|
} else {
|
|
247
342
|
itemChild = this.renderArrayItemRO(h, item, i)
|
|
248
|
-
itemKey = this.cached(`item-key-${i}`, { item }, () => {
|
|
249
|
-
|
|
250
|
-
})
|
|
251
|
-
if (!this.fullOptions.disableSorting) {
|
|
252
|
-
cardStyle = 'cursor: move;'
|
|
253
|
-
}
|
|
343
|
+
itemKey = this.cached(`item-key-${i}`, { item }, () => `${i}-${new Date().getTime()}`)
|
|
344
|
+
if (sortable) cardStyle = 'cursor: move;'
|
|
254
345
|
}
|
|
255
346
|
|
|
256
347
|
const titleClass = 'py-2 pr-2 ' + this.fullOptions.arrayItemsTitlesClasses[this.sectionDepth] || this.fullOptions.arrayItemsTitlesClasses[this.fullOptions.arrayItemsTitlesClasses.length - 1]
|
|
@@ -291,7 +382,7 @@ export default {
|
|
|
291
382
|
})
|
|
292
383
|
}
|
|
293
384
|
|
|
294
|
-
let itemClass = '
|
|
385
|
+
let itemClass = 'py-1 vjsf-array-item'
|
|
295
386
|
if (isCurrentInlineEdit) itemClass += ' vjsf-array-item-active'
|
|
296
387
|
return h('v-col', { props: this.fullOptions.arrayItemColProps, class: itemClass, key: itemKey }, [
|
|
297
388
|
h('v-card', {
|
|
@@ -301,18 +392,26 @@ export default {
|
|
|
301
392
|
}, cardChildren)
|
|
302
393
|
])
|
|
303
394
|
})
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
let newValue
|
|
398
|
+
const list = !sortable ? h('v-row', { class: 'vjsf-array' }, listItems) : h('draggable', {
|
|
399
|
+
props: { value: this.value },
|
|
400
|
+
attrs: { group: this.fullSchema['x-arrayGroup'] || this.fullKey, ...this.fullOptions.sortableOptions },
|
|
401
|
+
class: 'row draggable vjsf-array',
|
|
402
|
+
on: {
|
|
403
|
+
change: async (evt) => {
|
|
404
|
+
if (evt.added) await this.$nextTick()
|
|
309
405
|
this.editabledArrayProp.editItem = null
|
|
310
406
|
this.editabledArrayProp.currentDialog = null
|
|
311
|
-
this.input(
|
|
407
|
+
this.input(newValue)
|
|
312
408
|
this.change()
|
|
313
409
|
this.shouldValidate = true
|
|
314
|
-
}
|
|
315
|
-
|
|
410
|
+
},
|
|
411
|
+
input: async (value) => {
|
|
412
|
+
newValue = value
|
|
413
|
+
}
|
|
414
|
+
} }, listItems)
|
|
316
415
|
|
|
317
416
|
return [header, list]
|
|
318
417
|
}
|
|
@@ -144,7 +144,6 @@ export default {
|
|
|
144
144
|
h('v-card-text', { class: { 'pa-0': true } }, [childProp]),
|
|
145
145
|
isLast ? null : h('v-card-actions', { class: { 'px-0': true } }, [h('v-btn', { props: { color: 'primary' },
|
|
146
146
|
on: { click: () => {
|
|
147
|
-
console.log(childProp)
|
|
148
147
|
if (childProp.componentInstance.validate(true)) {
|
|
149
148
|
this.currentStep += 1
|
|
150
149
|
}
|
|
@@ -191,7 +190,8 @@ export default {
|
|
|
191
190
|
required: forceRequired || !!(this.fullSchema.required && this.fullSchema.required.includes(schema.key)),
|
|
192
191
|
options: { ...this.fullOptions, autofocus: this.fullOptions.autofocus && this.objectContainerChildrenCount === 1 },
|
|
193
192
|
optionsRoot: this.initialOptions,
|
|
194
|
-
sectionDepth
|
|
193
|
+
sectionDepth,
|
|
194
|
+
sharedData: this.sharedData
|
|
195
195
|
},
|
|
196
196
|
class: this.fullOptions.childrenClass,
|
|
197
197
|
scopedSlots: this.childScopedSlots(modelKey),
|
package/lib/utils/options.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mdiCalendar, mdiClock, mdiInformation, mdiPlus, mdiPencil, mdiDelete } from '@mdi/js'
|
|
1
|
+
import { mdiCalendar, mdiClock, mdiInformation, mdiPlus, mdiPencil, mdiDelete, mdiDotsVertical, mdiContentDuplicate, mdiContentCopy, mdiContentPaste } from '@mdi/js'
|
|
2
2
|
|
|
3
3
|
export const defaultOptions = {
|
|
4
4
|
locale: '',
|
|
@@ -45,13 +45,14 @@ export const defaultOptions = {
|
|
|
45
45
|
filesAsDataUrl: false,
|
|
46
46
|
hideTooltips: false,
|
|
47
47
|
disableSorting: false,
|
|
48
|
+
sortableOptions: {},
|
|
48
49
|
context: {},
|
|
49
50
|
rules: {},
|
|
50
51
|
initialValidation: 'defined',
|
|
51
52
|
idPrefix: '',
|
|
52
53
|
markdownit: {},
|
|
53
54
|
editMode: 'dialog',
|
|
54
|
-
arrayOperations: ['create', 'update', 'delete'],
|
|
55
|
+
arrayOperations: ['create', 'update', 'duplicate', 'copy', 'paste', 'delete'],
|
|
55
56
|
autofocus: false,
|
|
56
57
|
httpOptions: {},
|
|
57
58
|
selectAll: false,
|
|
@@ -94,7 +95,12 @@ export const localizedMessages = {
|
|
|
94
95
|
undo: 'Undo',
|
|
95
96
|
redo: 'Redo',
|
|
96
97
|
selectAll: 'Select all',
|
|
97
|
-
stepperContinue: 'continue'
|
|
98
|
+
stepperContinue: 'continue',
|
|
99
|
+
openMenu: 'open menu',
|
|
100
|
+
delete: 'delete',
|
|
101
|
+
duplicate: 'duplicate',
|
|
102
|
+
copy: 'copy',
|
|
103
|
+
paste: 'paste'
|
|
98
104
|
},
|
|
99
105
|
fr: {
|
|
100
106
|
required: 'Cette information est obligatoire',
|
|
@@ -129,7 +135,12 @@ export const localizedMessages = {
|
|
|
129
135
|
undo: 'Défaire',
|
|
130
136
|
redo: 'Refaire',
|
|
131
137
|
selectAll: 'Tout sélectionner',
|
|
132
|
-
stepperContinue: 'continuer'
|
|
138
|
+
stepperContinue: 'continuer',
|
|
139
|
+
openMenu: 'ouvrir le menu',
|
|
140
|
+
delete: 'supprimer',
|
|
141
|
+
duplicate: 'dupliquer',
|
|
142
|
+
copy: 'copier',
|
|
143
|
+
paste: 'coller'
|
|
133
144
|
},
|
|
134
145
|
es: {
|
|
135
146
|
required: 'Esta información es requerida',
|
|
@@ -234,7 +245,11 @@ export const iconSets = {
|
|
|
234
245
|
info: mdiInformation,
|
|
235
246
|
add: mdiPlus,
|
|
236
247
|
edit: mdiPencil,
|
|
237
|
-
delete: mdiDelete
|
|
248
|
+
delete: mdiDelete,
|
|
249
|
+
arrayMenu: mdiDotsVertical,
|
|
250
|
+
duplicate: mdiContentDuplicate,
|
|
251
|
+
copy: mdiContentCopy,
|
|
252
|
+
paste: mdiContentPaste
|
|
238
253
|
},
|
|
239
254
|
mdi: {
|
|
240
255
|
calendar: 'mdi-calendar',
|
|
@@ -242,7 +257,11 @@ export const iconSets = {
|
|
|
242
257
|
info: 'mdi-information',
|
|
243
258
|
add: 'mdi-plus',
|
|
244
259
|
edit: 'mdi-pencil',
|
|
245
|
-
delete: 'mdi-delete'
|
|
260
|
+
delete: 'mdi-delete',
|
|
261
|
+
arrayMenu: 'mdi-dots-vertical',
|
|
262
|
+
duplicate: 'mdi-plus-circle-multiple-outline',
|
|
263
|
+
copy: 'mdi-content-copy',
|
|
264
|
+
paste: 'mdi-content-paste'
|
|
246
265
|
},
|
|
247
266
|
md: {
|
|
248
267
|
calendar: 'event',
|
|
@@ -250,7 +269,11 @@ export const iconSets = {
|
|
|
250
269
|
info: 'info',
|
|
251
270
|
add: 'add',
|
|
252
271
|
edit: 'create',
|
|
253
|
-
delete: 'delete'
|
|
272
|
+
delete: 'delete',
|
|
273
|
+
arrayMenu: 'more_vert',
|
|
274
|
+
duplicate: 'control_point_duplicate',
|
|
275
|
+
copy: 'copy',
|
|
276
|
+
paste: 'paste'
|
|
254
277
|
},
|
|
255
278
|
fa: {
|
|
256
279
|
calendar: 'fa-calendar',
|
|
@@ -258,6 +281,10 @@ export const iconSets = {
|
|
|
258
281
|
info: 'fa-info',
|
|
259
282
|
add: 'fa-plus',
|
|
260
283
|
edit: 'fa-edit',
|
|
261
|
-
delete: 'fa-trash'
|
|
284
|
+
delete: 'fa-trash',
|
|
285
|
+
arrayMenu: 'fa-ellipsis-vertical',
|
|
286
|
+
duplicate: 'fa-layer-plus',
|
|
287
|
+
copy: 'fa-copy',
|
|
288
|
+
paste: 'fa-paste'
|
|
262
289
|
}
|
|
263
290
|
}
|
package/package.json
CHANGED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
<html>
|
|
2
|
-
<head>
|
|
3
|
-
<title>VJSF - test apps - compiled</title>
|
|
4
|
-
|
|
5
|
-
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
|
|
6
|
-
<link href="https://cdn.jsdelivr.net/npm/@mdi/font@6.x/css/materialdesignicons.min.css" rel="stylesheet">
|
|
7
|
-
<link href="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.min.css" rel="stylesheet">
|
|
8
|
-
<link href="/dist/main.css" rel="stylesheet">
|
|
9
|
-
</head>
|
|
10
|
-
<body>
|
|
11
|
-
<div id="app">
|
|
12
|
-
<v-app>
|
|
13
|
-
<v-main>
|
|
14
|
-
<v-container>
|
|
15
|
-
<h1>VJSF - Test app - Compiled</h1>
|
|
16
|
-
|
|
17
|
-
<h2>Very basic form</h2>
|
|
18
|
-
<v-form v-model="form1.valid">
|
|
19
|
-
<v-jsf :schema="form1.schema" :options="form1.options" v-model="form1.model"></v-jsf>
|
|
20
|
-
</v-form>
|
|
21
|
-
valid={{form1.valid}}, model={{form1.model}}
|
|
22
|
-
|
|
23
|
-
<h2>Form with draggable array elements</h2>
|
|
24
|
-
<v-form v-model="form2.valid">
|
|
25
|
-
<v-jsf :schema="form2.schema" :options="form2.options" v-model="form2.model"></v-jsf>
|
|
26
|
-
</v-form>
|
|
27
|
-
valid={{form2.valid}}, model={{form2.model}}
|
|
28
|
-
</v-container>
|
|
29
|
-
|
|
30
|
-
</v-main>
|
|
31
|
-
</v-app>
|
|
32
|
-
</div>
|
|
33
|
-
|
|
34
|
-
<script src="https://cdn.jsdelivr.net/npm/vue@2.x/dist/vue.js"></script>
|
|
35
|
-
<script src="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.js"></script>
|
|
36
|
-
<script src="/dist/main.js"></script>
|
|
37
|
-
<script src="/dist/third-party.js"></script>
|
|
38
|
-
<script>
|
|
39
|
-
Vue.component('VJsf', VJsf.default)
|
|
40
|
-
new Vue({
|
|
41
|
-
el: '#app',
|
|
42
|
-
vuetify: new Vuetify(),
|
|
43
|
-
data() {
|
|
44
|
-
return {
|
|
45
|
-
form1: {
|
|
46
|
-
valid: null,
|
|
47
|
-
schema: {
|
|
48
|
-
type: 'object',
|
|
49
|
-
properties: {
|
|
50
|
-
stringProp: { type: 'string', title: `I'm a string`, description: 'This description is used as a help message.' }
|
|
51
|
-
}
|
|
52
|
-
},
|
|
53
|
-
options: {},
|
|
54
|
-
model: {}
|
|
55
|
-
},
|
|
56
|
-
form2: {
|
|
57
|
-
valid: null,
|
|
58
|
-
schema: {
|
|
59
|
-
type: 'object',
|
|
60
|
-
properties: {
|
|
61
|
-
arrayProp: {
|
|
62
|
-
type: 'array',
|
|
63
|
-
items: {
|
|
64
|
-
type: 'object',
|
|
65
|
-
properties: {
|
|
66
|
-
stringProp: { type: 'string', title: `I'm a string` }
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
},
|
|
72
|
-
options: {},
|
|
73
|
-
model: {
|
|
74
|
-
arrayProp: [
|
|
75
|
-
{stringProp: 'value 1'},
|
|
76
|
-
{stringProp: 'value 2'}
|
|
77
|
-
]
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
})
|
|
83
|
-
</script>
|
|
84
|
-
</body>
|
|
85
|
-
</html>
|