@koumoul/vjsf 2.22.1 → 3.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/package.json +50 -86
  2. package/src/compat/v2.js +82 -0
  3. package/src/compile/index.js +32 -0
  4. package/src/compile/v-jsf-compiled.vue.ejs +83 -0
  5. package/src/components/fragments/node-slot.vue +49 -0
  6. package/src/components/fragments/section-header.vue +52 -0
  7. package/src/components/fragments/text-field-menu.vue +68 -0
  8. package/src/components/node.vue +60 -0
  9. package/src/components/nodes/checkbox.vue +27 -0
  10. package/src/components/nodes/color-picker.vue +43 -0
  11. package/src/components/nodes/date-picker.vue +45 -0
  12. package/src/components/nodes/date-time-picker.vue +20 -0
  13. package/src/components/nodes/expansion-panels.vue +52 -0
  14. package/src/components/nodes/list.vue +112 -0
  15. package/src/components/nodes/number-field.vue +35 -0
  16. package/src/components/nodes/one-of-select.vue +56 -0
  17. package/src/components/nodes/section.vue +30 -0
  18. package/src/components/nodes/select.vue +59 -0
  19. package/src/components/nodes/slider.vue +34 -0
  20. package/src/components/nodes/switch.vue +29 -0
  21. package/src/components/nodes/tabs.vue +63 -0
  22. package/src/components/nodes/text-field.vue +29 -0
  23. package/src/components/nodes/textarea.vue +29 -0
  24. package/src/components/nodes/time-picker.vue +7 -0
  25. package/src/components/nodes/vertical-tabs.vue +70 -0
  26. package/src/components/options.js +25 -0
  27. package/src/components/tree.vue +25 -0
  28. package/src/components/types.ts +59 -0
  29. package/src/components/vjsf.vue +168 -0
  30. package/src/index.js +2 -0
  31. package/src/utils/clone.js +3 -0
  32. package/src/utils/dates.js +52 -0
  33. package/src/utils/props.js +79 -0
  34. package/src/utils/slots.js +19 -0
  35. package/types/compat/v2.d.ts +10 -0
  36. package/types/compat/v2.d.ts.map +1 -0
  37. package/types/compile/index.d.ts +7 -0
  38. package/types/compile/index.d.ts.map +1 -0
  39. package/types/components/fragments/node-slot.vue.d.ts +47 -0
  40. package/types/components/fragments/node-slot.vue.d.ts.map +1 -0
  41. package/types/components/fragments/section-header.vue.d.ts +8 -0
  42. package/types/components/fragments/section-header.vue.d.ts.map +1 -0
  43. package/types/components/fragments/text-field-menu.vue.d.ts +20 -0
  44. package/types/components/fragments/text-field-menu.vue.d.ts.map +1 -0
  45. package/types/components/node.vue.d.ts +10 -0
  46. package/types/components/node.vue.d.ts.map +1 -0
  47. package/types/components/nodes/checkbox.vue.d.ts +10 -0
  48. package/types/components/nodes/checkbox.vue.d.ts.map +1 -0
  49. package/types/components/nodes/color-picker.vue.d.ts +10 -0
  50. package/types/components/nodes/color-picker.vue.d.ts.map +1 -0
  51. package/types/components/nodes/date-picker.vue.d.ts +10 -0
  52. package/types/components/nodes/date-picker.vue.d.ts.map +1 -0
  53. package/types/components/nodes/date-time-picker.vue.d.ts +10 -0
  54. package/types/components/nodes/date-time-picker.vue.d.ts.map +1 -0
  55. package/types/components/nodes/expansion-panels.vue.d.ts +10 -0
  56. package/types/components/nodes/expansion-panels.vue.d.ts.map +1 -0
  57. package/types/components/nodes/list.vue.d.ts +10 -0
  58. package/types/components/nodes/list.vue.d.ts.map +1 -0
  59. package/types/components/nodes/number-field.vue.d.ts +27 -0
  60. package/types/components/nodes/number-field.vue.d.ts.map +1 -0
  61. package/types/components/nodes/one-of-select.vue.d.ts +10 -0
  62. package/types/components/nodes/one-of-select.vue.d.ts.map +1 -0
  63. package/types/components/nodes/section.vue.d.ts +10 -0
  64. package/types/components/nodes/section.vue.d.ts.map +1 -0
  65. package/types/components/nodes/select.vue.d.ts +10 -0
  66. package/types/components/nodes/select.vue.d.ts.map +1 -0
  67. package/types/components/nodes/slider.vue.d.ts +10 -0
  68. package/types/components/nodes/slider.vue.d.ts.map +1 -0
  69. package/types/components/nodes/switch.vue.d.ts +10 -0
  70. package/types/components/nodes/switch.vue.d.ts.map +1 -0
  71. package/types/components/nodes/tabs.vue.d.ts +10 -0
  72. package/types/components/nodes/tabs.vue.d.ts.map +1 -0
  73. package/types/components/nodes/text-field copy.vue.d.ts +10 -0
  74. package/types/components/nodes/text-field copy.vue.d.ts.map +1 -0
  75. package/types/components/nodes/text-field.vue.d.ts +27 -0
  76. package/types/components/nodes/text-field.vue.d.ts.map +1 -0
  77. package/types/components/nodes/textarea.vue.d.ts +27 -0
  78. package/types/components/nodes/textarea.vue.d.ts.map +1 -0
  79. package/types/components/nodes/time-picker.vue.d.ts +3 -0
  80. package/types/components/nodes/time-picker.vue.d.ts.map +1 -0
  81. package/types/components/nodes/vertical-tabs.vue.d.ts +10 -0
  82. package/types/components/nodes/vertical-tabs.vue.d.ts.map +1 -0
  83. package/types/components/options.d.ts +3 -0
  84. package/types/components/options.d.ts.map +1 -0
  85. package/types/components/tree.vue.d.ts +10 -0
  86. package/types/components/tree.vue.d.ts.map +1 -0
  87. package/types/components/types.d.ts +71 -0
  88. package/types/components/types.d.ts.map +1 -0
  89. package/types/components/v-jsf.vue.d.ts +13 -0
  90. package/types/components/v-jsf.vue.d.ts.map +1 -0
  91. package/types/components/vjsf.vue.d.ts +13 -0
  92. package/types/components/vjsf.vue.d.ts.map +1 -0
  93. package/types/index.d.ts +3 -0
  94. package/types/index.d.ts.map +1 -0
  95. package/types/utils/clone.d.ts +3 -0
  96. package/types/utils/clone.d.ts.map +1 -0
  97. package/types/utils/dates.d.ts +7 -0
  98. package/types/utils/dates.d.ts.map +1 -0
  99. package/types/utils/props.d.ts +20 -0
  100. package/types/utils/props.d.ts.map +1 -0
  101. package/types/utils/slots.d.ts +7 -0
  102. package/types/utils/slots.d.ts.map +1 -0
  103. package/.eslintignore +0 -9
  104. package/.eslintrc.js +0 -38
  105. package/.github/workflows/scrape-doc.yml +0 -14
  106. package/.nvmrc +0 -1
  107. package/CONTRIBUTE.md +0 -61
  108. package/FUNDING.yml +0 -1
  109. package/README.md +0 -19
  110. package/babel.config.js +0 -4
  111. package/dist/main.css +0 -67
  112. package/dist/main.js +0 -2
  113. package/dist/main.js.LICENSE.txt +0 -10
  114. package/dist/third-party.js +0 -8
  115. package/dist/third-party.js.LICENSE.txt +0 -8
  116. package/lib/VJsf.css +0 -67
  117. package/lib/VJsf.js +0 -117
  118. package/lib/VJsfNoDeps.js +0 -517
  119. package/lib/deps/third-party.js +0 -16
  120. package/lib/mixins/ColorProperty.js +0 -45
  121. package/lib/mixins/DateProperty.js +0 -170
  122. package/lib/mixins/Dependent.js +0 -69
  123. package/lib/mixins/EditableArray.js +0 -418
  124. package/lib/mixins/FileProperty.js +0 -81
  125. package/lib/mixins/MarkdownEditor.js +0 -183
  126. package/lib/mixins/ObjectContainer.js +0 -351
  127. package/lib/mixins/SelectProperty.js +0 -400
  128. package/lib/mixins/SimpleProperty.js +0 -165
  129. package/lib/mixins/Tooltip.js +0 -42
  130. package/lib/mixins/Validatable.js +0 -119
  131. package/lib/utils/expr-eval-parser.js +0 -21
  132. package/lib/utils/is-cyclic.js +0 -34
  133. package/lib/utils/json-refs.js +0 -209
  134. package/lib/utils/options.js +0 -328
  135. package/lib/utils/rules.js +0 -81
  136. package/lib/utils/schema.js +0 -100
  137. package/lib/utils/select.js +0 -141
  138. package/webpack.config.js +0 -46
package/lib/VJsfNoDeps.js DELETED
@@ -1,517 +0,0 @@
1
- import copy from 'fast-copy'
2
- import { deepEqual } from 'fast-equals'
3
- import jrefs from './utils/json-refs'
4
- import schemaUtils from './utils/schema'
5
- import { defaultOptions, iconSets, localizedMessages, formats } from './utils/options'
6
- import { getRules } from './utils/rules'
7
- // import isCyclic from './utils/is-cyclic'
8
- import ObjectContainer from './mixins/ObjectContainer'
9
- import DateProperty from './mixins/DateProperty'
10
- import SimpleProperty from './mixins/SimpleProperty'
11
- import FileProperty from './mixins/FileProperty'
12
- import ColorProperty from './mixins/ColorProperty'
13
- import SelectProperty from './mixins/SelectProperty'
14
- import EditableArray from './mixins/EditableArray'
15
- import MarkdownEditor from './mixins/MarkdownEditor'
16
- import Tooltip from './mixins/Tooltip'
17
- import Validatable from './mixins/Validatable'
18
- import Dependent from './mixins/Dependent'
19
- import exprEvalParser from './utils/expr-eval-parser'
20
- import expr from 'property-expr'
21
- import debug from 'debug'
22
-
23
- const debugExpr = debug('vjsf:expr')
24
- debugExpr.log = console.log.bind(console)
25
-
26
- const mountingIncs = {}
27
-
28
- export default {
29
- name: 'VJsf',
30
- // components,
31
- mixins: [
32
- ObjectContainer,
33
- SimpleProperty,
34
- DateProperty,
35
- ColorProperty,
36
- SelectProperty,
37
- FileProperty,
38
- EditableArray,
39
- MarkdownEditor,
40
- Tooltip,
41
- Validatable,
42
- Dependent
43
- ],
44
- inject: ['theme'],
45
- props: {
46
- schema: { type: Object, required: true },
47
- value: { required: true },
48
- options: { type: Object },
49
- optionsRoot: { type: Object },
50
- modelRoot: { type: [Object, Array, String, Number, Boolean] },
51
- modelKey: { type: [String, Number], default: 'root' },
52
- parentKey: { type: String, default: '' },
53
- required: { type: Boolean, default: false },
54
- sectionDepth: { type: Number, default: 0 },
55
- sharedData: { type: Object, default: () => ({}) },
56
- showSectionTitle: { type: Boolean, default: false }
57
- },
58
- data() {
59
- return {
60
- loading: false,
61
- fullSchema: null
62
- }
63
- },
64
- computed: {
65
- initialOptions() {
66
- return this.fullKey === 'root' ? (this.options || {}) : this.optionsRoot
67
- },
68
- fullOptions() {
69
- const _global = (typeof window !== 'undefined' && window) || (typeof global !== 'undefined' && global) || {}
70
- defaultOptions.locale = (this.$vuetify.lang && this.$vuetify.lang.current) || 'en'
71
- defaultOptions.defaultLocale = (this.$vuetify.lang && this.$vuetify.lang.defaultLocale) || 'en'
72
- const fullOptions = Object.assign({}, defaultOptions, this.options || {}, this.resolvedSchema['x-options'] || {})
73
-
74
- fullOptions.markdown = fullOptions.markdown ||
75
- (_global.markdownit && (text => text ? _global.markdownit(fullOptions.markdownit).render(text) : '')) ||
76
- ((text) => text || '')
77
- fullOptions.memMarkdown = fullOptions.memMarkdown || (text => {
78
- this._vjsf_markdown = this._vjsf_markdown || {}
79
- const key = text + ''
80
- this._vjsf_markdown[key] = this._vjsf_markdown[key] || fullOptions.markdown(text)
81
- return this._vjsf_markdown[key]
82
- })
83
-
84
- fullOptions.httpLib = fullOptions.httpLib || this.axios || this.$http || this.$axios || _global.axios
85
-
86
- // validator function generator is either given or prepared using ajv if present in the context
87
- if (!fullOptions.validator) {
88
- const ajvLocalize = fullOptions.ajvLocalize || _global.ajvLocalize
89
- const ajvAddFormats = fullOptions.ajvAddFormats || _global.ajvAddFormats
90
- const localizeAjv = !!ajvLocalize && fullOptions.locale && ajvLocalize[fullOptions.locale]
91
- let ajv = fullOptions.ajv
92
- if (!ajv) {
93
- const Ajv = fullOptions.Ajv || _global.Ajv || (_global.ajv7 && _global.ajv7.default) || (_global.ajv2019 && _global.ajv2019.default)
94
- // TODO: use strict mode but remove our x-* annotations before
95
- if (Ajv) {
96
- ajv = new Ajv(localizeAjv ? { allErrors: true, messages: false, strict: false } : { strict: false })
97
- if (ajvAddFormats) ajvAddFormats(ajv)
98
- ajv.addFormat('hexcolor', /^#[0-9A-Fa-f]{6,8}$/)
99
- }
100
- }
101
- if (ajv) {
102
- fullOptions.validator = (schema) => {
103
- const validate = ajv.compile(schema)
104
- return (model) => {
105
- const valid = validate(model)
106
- if (!valid) {
107
- if (localizeAjv) {
108
- ajvLocalize[fullOptions.locale](validate.errors)
109
- }
110
- return ajv.errorsText(validate.errors, { dataVar: '' })
111
- }
112
- }
113
- }
114
- }
115
- }
116
- fullOptions.iconfont = (this.$vuetify.icons && this.$vuetify.icons.iconfont) || 'mdi'
117
- // importing default icon fonts from vuetify
118
- if (!fullOptions.defaultIcons) {
119
- const vuetifyCustomIcons = {}
120
- for (const [key, value] of Object.entries(this.$vuetify.icons.values)) {
121
- vuetifyCustomIcons[key] = value.props ? value.props.name : value
122
- }
123
- fullOptions.defaultIcons = { ...iconSets[fullOptions.iconfont], ...vuetifyCustomIcons }
124
- fullOptions.icons = { ...fullOptions.defaultIcons, ...fullOptions.icons }
125
- }
126
-
127
- fullOptions.messages = { ...(localizedMessages[fullOptions.defaultLocale] || localizedMessages.en), ...(localizedMessages[fullOptions.locale] || localizedMessages.en), ...fullOptions.messages }
128
- fullOptions.formats = { ...formats, ...fullOptions.formats }
129
- if (fullOptions.deleteReadOnly) fullOptions.hideReadOnly = true
130
- return fullOptions
131
- },
132
- resolvedSchema() {
133
- if (this.modelKey === 'root') {
134
- const options = this.options || {}
135
- const locale = options.locale || options.defaultLocale || 'en'
136
- const defaultLocale = options.defaultLocale || 'en'
137
- return jrefs.resolve(
138
- this.schema,
139
- { '~$locale~': locale === defaultLocale ? locale : [locale, defaultLocale] }
140
- )
141
- } else {
142
- return this.schema
143
- }
144
- },
145
- htmlDescription() {
146
- return this.fullOptions.markdown(this.fullSchema && this.fullSchema.description)
147
- },
148
- fullKey() {
149
- return (this.parentKey + this.modelKey).replace('root.', '')
150
- },
151
- label() {
152
- if (!this.fullSchema) return
153
- if ((this.fullSchema.readOnly || this.fullOptions.readOnlyArrayItem) && this.fullOptions.hideReadOnlyLabels) return
154
- return this.fullSchema.title || (typeof this.modelKey === 'string' ? this.modelKey : '')
155
- },
156
- display() {
157
- if (!this.fullSchema) return
158
- return this.modelKey === 'root' && this.fullOptions.rootDisplay ? this.fullOptions.rootDisplay : this.fullSchema['x-display']
159
- },
160
- customTag() {
161
- if (!this.fullSchema) return
162
- return this.fullSchema['x-tag']
163
- },
164
- rules() {
165
- if (!this.fullSchema) return
166
- return getRules(this.schema, this.fullSchema, this.fullOptions, this.required, this.isOneOfSelect)
167
- },
168
- disabled() {
169
- if (!this.fullSchema) return
170
- return this.fullOptions.disableAll || this.fullSchema.readOnly
171
- },
172
- separator() {
173
- if (!this.fullSchema && this.fullSchema.type !== 'string') return
174
- return this.fullSchema.separator || this.fullSchema['x-separator']
175
- },
176
- slotName() {
177
- if (!this.fullSchema) return
178
- return this.fullSchema['x-display'] && this.fullSchema['x-display'].startsWith('custom-') ? this.fullSchema['x-display'] : this.fullKey
179
- },
180
- slotParams() {
181
- if (!this.fullSchema) return
182
- return {
183
- value: this.value,
184
- modelKey: this.modelKey,
185
- schema: this.schema,
186
- fullKey: this.fullKey,
187
- fullSchema: this.fullSchema,
188
- label: this.label,
189
- disabled: this.disabled,
190
- required: this.required,
191
- rules: this.rules,
192
- options: this.fullOptions,
193
- htmlDescription: this.htmlDescription,
194
- on: {
195
- input: (e) => this.input(e instanceof Event ? e.target.value : e),
196
- change: () => this.change()
197
- }
198
- }
199
- },
200
- dashKey() {
201
- return this.fullKey.replace(/\./g, '-')
202
- },
203
- // props common to many vuetify fields
204
- commonFieldProps() {
205
- if (!this.fullSchema) return
206
- const value = this.separator && typeof this.value === 'string' ? this.value.split(this.separator) : this.value
207
- return {
208
- value,
209
- inputValue: value,
210
- label: this.label,
211
- name: this.fullKey,
212
- id: this.fullOptions.idPrefix + this.dashKey,
213
- disabled: this.disabled,
214
- rules: this.rules,
215
- required: this.required,
216
- autofocus: this.fullOptions.autofocus,
217
- ...((this.fullSchema.readOnly || this.fullOptions.readOnlyArrayItem) ? this.fullOptions.readOnlyFieldProps : {}),
218
- ...this.fullOptions.fieldProps,
219
- ...this.fullSchema['x-props']
220
- }
221
- },
222
- propertyClass() {
223
- if (!this.fullSchema) return
224
- return `vjsf-property vjsf-property-${this.dashKey} pa-0 ${this.fullSchema['x-class'] || ''} ${(this.fullSchema.readOnly || this.fullOptions.readOnlyArrayItem) ? 'read-only' : ''}`
225
- .replace(/ {2}/g, ' ').trim()
226
- },
227
- xSlots() {
228
- if (!this.fullSchema) return
229
- return { ...this.fullSchema['x-slots'] }
230
- },
231
- formattedValue() {
232
- if (!this.fullSchema) return
233
- return this.value && this.fullSchema.format && this.fullOptions.formats[this.fullSchema.format] && this.fullOptions.formats[this.fullSchema.format](this.value, this.fullOptions.locale)
234
- },
235
- directives() {
236
- if (!this.fullSchema) return
237
- return this.fullSchema['x-directives']
238
- }
239
- },
240
- watch: {
241
- fullSchema: {
242
- handler() {
243
- if (!this.fullSchema) return
244
- this.initFromSchema()
245
- this.initValidation()
246
- this.updateSelectItems()
247
- }
248
- }
249
- },
250
- mounted() {
251
- mountingIncs[this.fullKey] = (mountingIncs[this.fullKey] || 0) + 1
252
- // DEVS NOTE: uncomment this when fighting against infinite loops
253
- // if infinite loop occurs again have a look here https://github.com/koumoul-dev/vuetify-jsonschema-form/issues/289
254
- // and here https://github.com/koumoul-dev/vuetify-jsonschema-form/commit/fba002dea2438f5ea2ff5be1622ac79b35056eff
255
- /* if (mountingIncs[this.fullKey] === 100) {
256
- console.log(mountingIncs)
257
- throw new Error('detected infinite mounting loop: ' + this.fullKey)
258
- } */
259
-
260
- // optimize the watcher used to reprocess fullSchema so that we trigger less re-render of components
261
- let watcher = 'resolvedSchema'
262
- if (this.resolvedSchema.dependencies || this.resolvedSchema.if) {
263
- watcher = (vm) => [vm.resolvedSchema, vm.value]
264
- }
265
- this.$watch(watcher, () => {
266
- const fullSchema = schemaUtils.prepareFullSchema(this.resolvedSchema, this.value, this.fullOptions)
267
- // kinda hackish but prevents triggering large rendering chains when nothing meaningful changes
268
- if (!deepEqual(fullSchema, this.fullSchema)) this.fullSchema = fullSchema
269
- }, {
270
- immediate: true,
271
- deep: true
272
- })
273
- },
274
- render(h) {
275
- this.renderInc = (this.renderInc || 0) + 1
276
- // DEVS NOTE: uncomment this when fighting against infinite loops
277
- /* if (this.renderInc === 100) {
278
- throw new Error('detected infinite rendering loop: ' + this.fullKey)
279
- } */
280
-
281
- // a few cases where we don't render anything
282
- if (!this.fullSchema) return
283
- if (this.fullSchema.const !== undefined) return
284
- if (this.display === 'hidden') return
285
- if (this.fullSchema.readOnly && this.fullOptions.hideReadOnly) return
286
- if (this.fullOptions.readOnlyArrayItem && this.fullOptions.hideInArrayItem) return
287
- if ((this.fullSchema.readOnly || this.fullOptions.readOnlyArrayItem) && this.fullOptions.hideReadOnlyEmpty && [null, undefined, ''].includes(this.value)) return
288
- if (this.fullSchema['x-if'] && !this.getFromExpr(this.fullSchema['x-if'])) return
289
-
290
- const children = []
291
- if (this.$scopedSlots.before) children.push(this.$scopedSlots.before(this.slotParams))
292
- else if (this.$slots.before) this.$slots.before.forEach(node => children.push(node))
293
- else if (this.xSlots.before) children.push(h('div', { domProps: { innerHTML: this.fullOptions.memMarkdown(this.xSlots.before) } }))
294
-
295
- if (this.$scopedSlots.default) {
296
- children.push(this.$scopedSlots.default(this.slotParams))
297
- } else if (this.fullSchema['x-display'] && this.fullSchema['x-display'] && this.$scopedSlots[this.fullSchema['x-display']]) {
298
- children.push(this.$scopedSlots[this.fullSchema['x-display']](this.slotParams))
299
- } else {
300
- const mainChildren = this.renderDateProp(h) ||
301
- this.renderColorProp(h) ||
302
- this.renderSelectProp(h) ||
303
- this.renderFileProp(h) ||
304
- this.renderMarkdownProp(h) ||
305
- this.renderSimpleProp(h) ||
306
- this.renderObjectContainer(h) ||
307
- this.renderEditableArray(h) || []
308
- mainChildren.forEach(child => children.push(child))
309
- }
310
-
311
- if (this.$scopedSlots.after) children.push(this.$scopedSlots.after(this.slotParams))
312
- else if (this.$slots.after) this.$slots.after.forEach(node => children.push(node))
313
- else if (this.xSlots.after) {
314
- children.push(h('div', { domProps: { innerHTML: this.fullOptions.memMarkdown(this.xSlots.after) } }))
315
- }
316
-
317
- let colProps = { ...this.fullOptions.fieldColProps }
318
- if (this.fullSchema['x-cols']) {
319
- if (typeof this.fullSchema['x-cols'] === 'object') {
320
- colProps = { ...colProps, ...this.fullSchema['x-cols'] }
321
- } else {
322
- colProps.cols = this.fullSchema['x-cols']
323
- }
324
- }
325
- return h('v-col', { props: colProps, class: this.propertyClass, style: this.fullSchema['x-style'] || '' }, children)
326
- },
327
- methods: {
328
- cached(key, params, fn) {
329
- this._vjsf_cache = this._vjsf_cache || {}
330
- if (!this._vjsf_cache[key] || !deepEqual(this._vjsf_cache[key].params, params)) {
331
- // console.log('fill cache', key, this.fullKey)
332
- this._vjsf_cache[key] = { params: copy(params), value: fn() }
333
- } else {
334
- // console.log('use cache', key, this.fullKey)
335
- }
336
- return this._vjsf_cache[key].value
337
- },
338
- // used by all functionalities that require looking into the data or the context (x-if, fromData, etc)
339
- getFromExpr(exp) {
340
- const expData = this.getExprNode()
341
- expData.modelRoot = this.modelRoot
342
- expData.root = this.modelRoot
343
- expData.model = this.value
344
- expData.context = this.options.context
345
-
346
- this._vjsf_getters = this._vjsf_getters || {}
347
-
348
- // newFunction can only be defined on main options (not x-options to prevent injection)
349
- if (this.initialOptions.evalMethod === 'newFunction') {
350
- debugExpr(`evaluate expression "${exp}" with newFunction method`, expData)
351
- // use a powerful meta-programming approach with "new Function", not safe if the schema is user-submitted
352
- // eslint-disable-next-line no-new-func
353
- this._vjsf_getters[exp] = this._vjsf_getters[exp] || new Function(...Object.keys(expData), `return ${exp}`)
354
- const result = this._vjsf_getters[exp](...Object.values(expData))
355
- debugExpr(`result`, result)
356
- return result
357
- } else if (this.fullOptions.evalMethod === 'evalExpr') {
358
- debugExpr(`evaluate expression "${exp}" with exprEval method`, expData)
359
- // TODO: conserve compiled expression for reuse ?
360
- const result = exprEvalParser.evaluate(exp, expData)
361
- debugExpr(result)
362
- return result
363
- } else {
364
- exp = this.prefixExpr(exp)
365
- debugExpr(`evaluate expression "${exp}" with propertyExpr method`, expData)
366
- // otherwise a safer but not as powerful deep getter method
367
- this._vjsf_getters[exp] = this._vjsf_getters[exp] || expr.getter(exp, true)
368
- const result = this._vjsf_getters[exp](expData)
369
- debugExpr(`result`, result)
370
- return result
371
- }
372
- },
373
- // used by getFromExpr to support simpler expressions that look into the root model by default
374
- prefixExpr(key) {
375
- if (key.startsWith('context.') || key.startsWith('model.') || key.startsWith('value.') || key.startsWith('modelRoot.') || key.startsWith('root.') || key.startsWith('parent.')) return key
376
- // no specific prefix found, we use modelRoot for retro-compatibility
377
- if (this.modelRoot) return 'root.' + key
378
- return 'model.' + key
379
- },
380
- renderPropSlots(h) {
381
- const slots = []
382
- Object.keys(this.xSlots).forEach(slot => {
383
- slots.push(h('div', { slot, domProps: { innerHTML: this.fullOptions.memMarkdown(this.xSlots[slot]) } }))
384
- })
385
- Object.keys(this.$slots).forEach(slot => {
386
- slots.push(h('template', { slot }, this.$slots[slot]))
387
- })
388
- return slots
389
- },
390
- async change(fastForward = true) {
391
- if (!this.changed) return
392
- // let input events be interpreted before sending this.value in change event
393
- await this.$nextTick()
394
-
395
- // store all current promises in sharedData.asyncOperations so that we can delay change events
396
- // until after a user interaction has finished having async consequencies
397
- this.sharedData.asyncOperations = this.sharedData.asyncOperations || {}
398
- while (Object.keys(this.sharedData.asyncOperations).length) {
399
- for (const key in this.sharedData.asyncOperations) {
400
- await this.sharedData.asyncOperations[key]
401
- }
402
- await this.$nextTick()
403
- }
404
- this.updateSelectItems()
405
- if (fastForward) this.fastForwardEvent('change-child', { fullKey: this.fullKey, value: this.value })
406
- this.$emit('change', this.value)
407
- this.changed = false
408
- },
409
- input(value, initial = false, fastForward = true) {
410
- if (Array.isArray(value) && this.separator) value = value.join(this.separator)
411
- if (value === null || value === undefined) {
412
- if (this.fullSchema.nullable) {
413
- if (this.value !== null) {
414
- this.changed = true
415
- if (fastForward) this.fastForwardEvent('input-child', { fullKey: this.fullKey, value: null, oldValue: this.value })
416
- this.$emit('input', null)
417
- } else if (initial) {
418
- if (fastForward) this.fastForwardEvent('input-child', { fullKey: this.fullKey, value: null, oldValue: this.value })
419
- this.$emit('input', null)
420
- }
421
- } else {
422
- if (this.value !== undefined) {
423
- this.changed = true
424
- if (fastForward) this.fastForwardEvent('input-child', { fullKey: this.fullKey, value: undefined, oldValue: this.value })
425
- this.$emit('input', undefined)
426
- }
427
- }
428
- } else {
429
- if (!deepEqual(value, this.value)) {
430
- this.changed = true
431
- // console.log(this.fullKey, isCyclic(value), value)
432
- if (fastForward) this.fastForwardEvent('input-child', { fullKey: this.fullKey, value, oldValue: this.value })
433
- this.$emit('input', value)
434
- }
435
- }
436
- },
437
- fixValueType(value, schema) {
438
- if ([null, undefined].includes(value)) return value
439
- if (schema.type === 'string' && typeof value !== 'string') return undefined
440
- if (schema.type === 'integer' && typeof value !== 'number') return undefined
441
- if (schema.type === 'number' && typeof value !== 'number') return undefined
442
- if (schema.type === 'boolean' && typeof value !== 'boolean') return undefined
443
- if (schema.type === 'array' && !Array.isArray(value)) return undefined
444
- if (schema.type === 'object' && (typeof value !== 'object' || Array.isArray(value))) return undefined
445
- return value
446
- },
447
- defaultValue(schema) {
448
- if (schema.readOnly && this.fullOptions.deleteReadOnly) return undefined
449
- if (schema.type === 'object' && !schema['x-fromUrl'] && !schema['x-fromData'] && !schema.enum) return {}
450
- if (schema.type === 'array') return []
451
- return null
452
- },
453
- fixProperties(value) {
454
- if (this.fullSchema.type !== 'object' || !value) return value
455
-
456
- const nonSchematized = (!this.fullSchema.properties || !this.fullSchema.properties.length) && (!Object.keys(this.subModels).length || !!this.fullSchema['x-fromData'] || !!this.fullSchema['x-fromUrl'])
457
- if (nonSchematized) return value
458
-
459
- value = { ...value }
460
-
461
- // cleanup extra properties
462
- if (this.fullOptions.removeAdditionalProperties || this.fullSchema.additionalProperties === false) {
463
- Object.keys(value).forEach(key => {
464
- if (!(this.fullSchema.properties || []).find(p => p.key === key)) {
465
- // console.log(`Remove key ${this.modelKey}.${key}`)
466
- delete value[key]
467
- }
468
- })
469
- }
470
-
471
- // apply submodels
472
- Object.keys(this.subModels).forEach(subModel => {
473
- Object.keys(this.subModels[subModel]).forEach(key => {
474
- // special case, ignore subschema switch key coming from another submodel
475
- const localProperty = this.fullSchema.properties.find(p => p.key === key)
476
- if (localProperty && localProperty.const) return
477
-
478
- if (value[key] === this.subModels[subModel][key]) return
479
- value[key] = this.subModels[subModel][key]
480
- })
481
- })
482
- return value
483
- },
484
- initFromSchema() {
485
- // initiallyDefined will by used in Validatable.js to perform initial validation or not
486
- this.initiallyDefined = this.value !== undefined && this.value !== null
487
- // we cannot consider empty objects and empty arrays as "defined" as they might have been initialized by vjsf itself
488
- if (this.fullSchema.type === 'array') this.initiallyDefined = !!(this.value && this.value.length)
489
- if (this.fullSchema.type === 'object') this.initiallyDefined = !!(this.value && Object.keys(this.value).length)
490
-
491
- // console.log('Init from schema', this.modelKey)
492
- if (this.fullSchema.readOnly && this.fullOptions.deleteReadOnly) {
493
- return this.input(undefined)
494
- }
495
- let value = this.value
496
-
497
- // create empty objects
498
- if (this.fullSchema.type === 'object' && [undefined, null].includes(value) && !this.isSelectProp) {
499
- value = {}
500
- }
501
- // in the special case of objects based on select remove empty objects
502
- if (this.fullSchema.type === 'object' && this.isSelectProp && value && Object.keys(value).length === 0) {
503
- value = undefined
504
- }
505
-
506
- // const always wins
507
- if (this.fullSchema.const !== undefined) value = this.fullSchema.const
508
- this.initSelectProp(value)
509
- this.initObjectContainer(value)
510
- // Cleanup arrays of empty items
511
- if (this.fullSchema.type === 'array') {
512
- value = this.value.filter(item => ![undefined, null].includes(item))
513
- }
514
- return this.input(this.fixProperties(value), true)
515
- }
516
- }
517
- }
@@ -1,16 +0,0 @@
1
- // import this module if you want to be sure that you get all dependancies
2
- // used by vjsf functionalities (color picker, etc.)
3
-
4
- import Vue from 'vue'
5
- import Draggable from 'vuedraggable'
6
- import markdownIt from 'markdown-it'
7
- import ajv from 'ajv'
8
- import ajvI18n from 'ajv-i18n'
9
- import ajvFormats from 'ajv-formats'
10
-
11
- const _global = (typeof window !== 'undefined' && window) || (typeof global !== 'undefined' && global) || {}
12
- _global.markdownit = markdownIt
13
- Vue.component('Draggable', Draggable)
14
- _global.Ajv = ajv
15
- _global.ajvLocalize = ajvI18n
16
- _global.ajvAddFormats = ajvFormats
@@ -1,45 +0,0 @@
1
- export default {
2
- computed: {
3
- isColorProp() {
4
- return this.resolvedSchema.type === 'string' && (this.resolvedSchema.format === 'hexcolor' || this.display === 'color-picker')
5
- }
6
- },
7
- methods: {
8
- renderColorProp(h) {
9
- if (!this.isColorProp) return
10
-
11
- const children = [this.renderTooltip(h, 'append')]
12
-
13
- children.push(h('v-menu', {
14
- props: { closeOnContentClick: false, closeOneClick: true, direction: 'bottom', offsetY: true },
15
- scopedSlots: {
16
- activator: ({ on }) => h('div', {
17
- on,
18
- style: `background-color: ${this.value};margin-left: 10px;`,
19
- class: this.value ? 'color-picker-trigger' : 'color-picker-trigger color-picker-trigger-empty'
20
- }),
21
- default: () => h('v-color-picker', {
22
- props: { flat: true, ...this.fullOptions.colorPickerProps, ...this.fullSchema['x-props'], value: this.value || '' },
23
- on: {
24
- input: val => {
25
- this.input(val)
26
- this.change()
27
- }
28
- }
29
- })
30
- }
31
- }))
32
- return [h('v-input', {
33
- props: {
34
- value: this.value,
35
- name: this.fullKey,
36
- label: this.label,
37
- required: this.required,
38
- rules: this.rules,
39
- disabled: this.disabled,
40
- ...this.fullOptions.fieldProps
41
- }
42
- }, children)]
43
- }
44
- }
45
- }