@ditojs/admin 2.1.3 → 2.2.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/dito-admin.es.js +1549 -1451
- package/dist/dito-admin.umd.js +4 -4
- package/dist/style.css +1 -1
- package/package.json +5 -5
- package/src/DitoContext.js +10 -10
- package/src/DitoTypeComponent.js +1 -0
- package/src/components/DitoContainer.vue +22 -10
- package/src/components/DitoCreateButton.vue +11 -8
- package/src/components/DitoDraggable.vue +45 -0
- package/src/components/DitoPane.vue +1 -1
- package/src/components/DitoPanel.vue +1 -1
- package/src/components/DitoSchema.vue +11 -6
- package/src/components/DitoSchemaInlined.vue +1 -0
- package/src/components/DitoTreeItem.vue +3 -2
- package/src/components/index.js +1 -0
- package/src/mixins/DataMixin.js +3 -3
- package/src/mixins/DitoMixin.js +23 -10
- package/src/mixins/RouteMixin.js +1 -1
- package/src/mixins/SortableMixin.js +2 -6
- package/src/mixins/SourceMixin.js +0 -5
- package/src/mixins/TypeMixin.js +40 -17
- package/src/styles/_pulldown.scss +9 -12
- package/src/types/DitoTypeButton.vue +12 -9
- package/src/types/DitoTypeCode.vue +1 -0
- package/src/types/DitoTypeComponent.vue +1 -0
- package/src/types/DitoTypeLabel.vue +2 -1
- package/src/types/DitoTypeList.vue +4 -2
- package/src/types/DitoTypeMarkup.vue +2 -0
- package/src/types/DitoTypeObject.vue +2 -0
- package/src/types/DitoTypePanel.vue +1 -0
- package/src/types/DitoTypeSection.vue +1 -1
- package/src/types/DitoTypeTextarea.vue +1 -0
- package/src/types/DitoTypeTreeList.vue +2 -0
- package/src/types/DitoTypeUpload.vue +5 -2
- package/src/utils/accessor.js +1 -1
- package/src/utils/options.js +1 -0
- package/src/utils/schema.js +5 -15
- package/types/index.d.ts +3 -24
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ditojs/admin",
|
|
3
|
-
"version": "2.1
|
|
3
|
+
"version": "2.2.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Dito.js Admin is a schema based admin interface for Dito.js Server, featuring auto-generated views and forms and built with Vue.js",
|
|
6
6
|
"repository": "https://github.com/ditojs/dito/tree/master/packages/admin",
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
"not ie_mob > 0"
|
|
34
34
|
],
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@ditojs/ui": "^2.
|
|
37
|
-
"@ditojs/utils": "^2.
|
|
36
|
+
"@ditojs/ui": "^2.2.0",
|
|
37
|
+
"@ditojs/utils": "^2.2.0",
|
|
38
38
|
"@kyvg/vue3-notification": "^2.9.0",
|
|
39
39
|
"@lk77/vue3-color": "^3.0.6",
|
|
40
40
|
"@tiptap/core": "^2.0.3",
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"vue-upload-component": "^3.1.8"
|
|
74
74
|
},
|
|
75
75
|
"devDependencies": {
|
|
76
|
-
"@ditojs/build": "^2.
|
|
76
|
+
"@ditojs/build": "^2.2.0",
|
|
77
77
|
"@vitejs/plugin-vue": "^4.1.0",
|
|
78
78
|
"@vue/compiler-sfc": "^3.2.47",
|
|
79
79
|
"pug": "^3.0.2",
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
"vite": "^4.2.1"
|
|
83
83
|
},
|
|
84
84
|
"types": "types",
|
|
85
|
-
"gitHead": "
|
|
85
|
+
"gitHead": "306d4d9ef2a0c989b026f1d1cd77f6d4fd60430b",
|
|
86
86
|
"scripts": {
|
|
87
87
|
"build": "vite build",
|
|
88
88
|
"watch": "yarn build --mode 'development' --watch",
|
package/src/DitoContext.js
CHANGED
|
@@ -103,27 +103,27 @@ export default class DitoContext {
|
|
|
103
103
|
return getLastDataPathIndex(this.parentItemDataPath)
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
+
// NOTE: While internally, we speak of `data`, in the API surface the
|
|
107
|
+
// term `item` is used for the data that relates to editing objects:
|
|
108
|
+
// If `data` isn't provided, we can determine it from rootData & dataPath:
|
|
106
109
|
get item() {
|
|
107
|
-
// NOTE: While internally, we speak of `data`, in the API surface the
|
|
108
|
-
// term `item` is used for the data that relates to editing objects:
|
|
109
|
-
// If `data` isn't provided, we can determine it from rootData & dataPath:
|
|
110
110
|
return get(this, 'data', () =>
|
|
111
111
|
getItem(this.rootItem, this.dataPath, this.nested)
|
|
112
112
|
)
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
// NOTE: `parentItem` isn't the closest data parent to `item`, it's the
|
|
116
|
-
// closest parent that isn't an array, e.g. for relations or nested JSON
|
|
117
|
-
//
|
|
118
|
-
//
|
|
119
|
-
//
|
|
120
|
-
//
|
|
116
|
+
// closest parent that isn't an array, e.g. for relations or nested JSON data.
|
|
117
|
+
// This is why the term `item` was chosen over `data`, e.g. VS the use of
|
|
118
|
+
// `parentData` in server-sided validation, which is the closest parent. If
|
|
119
|
+
// needed, we could expose this data here too, as we can do all sorts of data
|
|
120
|
+
// processing with `rootData` and `dataPath`.
|
|
121
121
|
get parentItem() {
|
|
122
|
-
const
|
|
122
|
+
const item = (
|
|
123
123
|
getParentItem(this.rootItem, this.dataPath, this.nested) ||
|
|
124
124
|
null
|
|
125
125
|
)
|
|
126
|
-
return
|
|
126
|
+
return item !== this.item ? item : null
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
get rootItem() {
|
package/src/DitoTypeComponent.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
:style="containerStyle"
|
|
6
6
|
)
|
|
7
7
|
DitoLabel(
|
|
8
|
-
v-if="
|
|
8
|
+
v-if="hasLabel"
|
|
9
9
|
:label="label"
|
|
10
10
|
:dataPath="labelDataPath"
|
|
11
11
|
:class="componentClass"
|
|
@@ -31,7 +31,7 @@ import { isString, isNumber } from '@ditojs/utils'
|
|
|
31
31
|
import DitoComponent from '../DitoComponent.js'
|
|
32
32
|
import DitoContext from '../DitoContext.js'
|
|
33
33
|
import { getSchemaAccessor } from '../utils/accessor.js'
|
|
34
|
-
import { getTypeComponent,
|
|
34
|
+
import { getTypeComponent, alignBottom, omitPadding } from '../utils/schema.js'
|
|
35
35
|
import { parseFraction } from '../utils/math.js'
|
|
36
36
|
|
|
37
37
|
// @vue/component
|
|
@@ -64,11 +64,12 @@ export default DitoComponent.component('DitoContainer', {
|
|
|
64
64
|
},
|
|
65
65
|
|
|
66
66
|
hasLabel() {
|
|
67
|
-
const {
|
|
68
|
-
const { label } = schema
|
|
67
|
+
const { label } = this.schema
|
|
69
68
|
return (
|
|
70
|
-
label !== false &&
|
|
71
|
-
|
|
69
|
+
label !== false && (
|
|
70
|
+
!!label ||
|
|
71
|
+
this.generateLabels && this.typeComponent?.generateLabel
|
|
72
|
+
)
|
|
72
73
|
)
|
|
73
74
|
},
|
|
74
75
|
|
|
@@ -122,9 +123,12 @@ export default DitoComponent.component('DitoContainer', {
|
|
|
122
123
|
|
|
123
124
|
containerClass() {
|
|
124
125
|
const { class: containerClass } = this.schema
|
|
126
|
+
const prefix = 'dito-container'
|
|
125
127
|
return {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
+
[`${prefix}--single`]: this.single,
|
|
129
|
+
[`${prefix}--has-label`]: this.hasLabel,
|
|
130
|
+
[`${prefix}--align-bottom`]: alignBottom(this.schema),
|
|
131
|
+
[`${prefix}--omit-padding`]: omitPadding(this.schema),
|
|
128
132
|
...(
|
|
129
133
|
isString(containerClass)
|
|
130
134
|
? { [containerClass]: true }
|
|
@@ -162,6 +166,7 @@ export default DitoComponent.component('DitoContainer', {
|
|
|
162
166
|
componentClass() {
|
|
163
167
|
const basisIsAuto = this.componentBasis === 'auto'
|
|
164
168
|
return {
|
|
169
|
+
// TODO: BEM
|
|
165
170
|
'dito-single': this.single,
|
|
166
171
|
'dito-disabled': this.componentDisabled,
|
|
167
172
|
'dito-width-fill': !basisIsAuto || this.componentWidth === 'fill',
|
|
@@ -183,6 +188,9 @@ export default DitoComponent.component('DitoContainer', {
|
|
|
183
188
|
@import '../styles/_imports';
|
|
184
189
|
|
|
185
190
|
.dito-container {
|
|
191
|
+
display: flex;
|
|
192
|
+
flex-flow: column;
|
|
193
|
+
align-items: flex-start;
|
|
186
194
|
// Needed for better vertical alignment:
|
|
187
195
|
align-self: stretch;
|
|
188
196
|
box-sizing: border-box;
|
|
@@ -196,7 +204,11 @@ export default DitoComponent.component('DitoContainer', {
|
|
|
196
204
|
padding: 0;
|
|
197
205
|
}
|
|
198
206
|
|
|
199
|
-
|
|
207
|
+
&--align-bottom {
|
|
208
|
+
justify-content: end; // To align components with and without labels.
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
&--omit-padding {
|
|
200
212
|
padding: 0;
|
|
201
213
|
|
|
202
214
|
> .dito-label {
|
|
@@ -204,7 +216,7 @@ export default DitoComponent.component('DitoContainer', {
|
|
|
204
216
|
}
|
|
205
217
|
}
|
|
206
218
|
|
|
207
|
-
|
|
219
|
+
&--single {
|
|
208
220
|
height: 100%; // So that list buttons can be sticky at the bottom;
|
|
209
221
|
}
|
|
210
222
|
}
|
|
@@ -14,8 +14,9 @@
|
|
|
14
14
|
v-for="(form, type) in forms"
|
|
15
15
|
)
|
|
16
16
|
a(
|
|
17
|
-
v-if="
|
|
18
|
-
|
|
17
|
+
v-if="shouldRender(form)"
|
|
18
|
+
v-show="shouldShow(form)"
|
|
19
|
+
:class="getFormClass(form, type)"
|
|
19
20
|
@mousedown.stop="onPulldownMouseDown(type)"
|
|
20
21
|
@mouseup="onPulldownMouseUp(type)"
|
|
21
22
|
) {{ getLabel(form) }}
|
|
@@ -59,13 +60,8 @@ export default DitoComponent.component('DitoCreateButton', {
|
|
|
59
60
|
},
|
|
60
61
|
|
|
61
62
|
methods: {
|
|
62
|
-
isCreatable(form) {
|
|
63
|
-
// Forms can be excluded from the list by providing `creatable: false`
|
|
64
|
-
return form.creatable !== false
|
|
65
|
-
},
|
|
66
|
-
|
|
67
63
|
createItem(form, type = null) {
|
|
68
|
-
if (this.
|
|
64
|
+
if (this.shouldRender(form) && !this.shouldDisable(form)) {
|
|
69
65
|
if (this.isInlined) {
|
|
70
66
|
this.sourceComponent.createItem(form, type)
|
|
71
67
|
} else {
|
|
@@ -79,6 +75,13 @@ export default DitoComponent.component('DitoCreateButton', {
|
|
|
79
75
|
}
|
|
80
76
|
},
|
|
81
77
|
|
|
78
|
+
getFormClass(form, type) {
|
|
79
|
+
return {
|
|
80
|
+
[`dito-type-${type}`]: true,
|
|
81
|
+
'dito-disabled': this.shouldDisable(form)
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
|
|
82
85
|
onPulldownSelect(type) {
|
|
83
86
|
this.createItem(this.forms[type], type)
|
|
84
87
|
this.setPulldownOpen(false)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<template lang="pug">
|
|
2
|
+
UseSortable(
|
|
3
|
+
v-if="draggable"
|
|
4
|
+
:tag="tag"
|
|
5
|
+
:modelValue="modelValue"
|
|
6
|
+
:options="options"
|
|
7
|
+
@update:modelValue="$emit('update:modelValue', $event)"
|
|
8
|
+
)
|
|
9
|
+
slot
|
|
10
|
+
component(
|
|
11
|
+
v-else
|
|
12
|
+
:is="tag"
|
|
13
|
+
)
|
|
14
|
+
slot
|
|
15
|
+
</template>
|
|
16
|
+
|
|
17
|
+
<script>
|
|
18
|
+
import DitoComponent from '../DitoComponent'
|
|
19
|
+
import { UseSortable } from '@vueuse/integrations/useSortable/component'
|
|
20
|
+
|
|
21
|
+
// @vue/component
|
|
22
|
+
export default DitoComponent.component('DitoDraggable', {
|
|
23
|
+
components: { UseSortable },
|
|
24
|
+
emits: ['update:modelValue'],
|
|
25
|
+
|
|
26
|
+
props: {
|
|
27
|
+
modelValue: {
|
|
28
|
+
type: Array,
|
|
29
|
+
required: true
|
|
30
|
+
},
|
|
31
|
+
tag: {
|
|
32
|
+
type: String,
|
|
33
|
+
default: 'div'
|
|
34
|
+
},
|
|
35
|
+
options: {
|
|
36
|
+
type: Object,
|
|
37
|
+
required: true
|
|
38
|
+
},
|
|
39
|
+
draggable: {
|
|
40
|
+
type: Boolean,
|
|
41
|
+
default: true
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
</script>
|
|
@@ -162,7 +162,7 @@ export default DitoComponent.component('DitoPane', {
|
|
|
162
162
|
margin-top: 0;
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
-
.dito-container
|
|
165
|
+
.dito-container--omit-padding > & {
|
|
166
166
|
// Clear margins set above again if parent is omitting padding.
|
|
167
167
|
margin: 0;
|
|
168
168
|
max-width: unset;
|
|
@@ -142,7 +142,7 @@ export default DitoComponent.component('DitoSchema', {
|
|
|
142
142
|
// Allow schema to provide more data through `schema.data`, vue-style:
|
|
143
143
|
...(
|
|
144
144
|
data && isFunction(data)
|
|
145
|
-
? data
|
|
145
|
+
? data(this.context)
|
|
146
146
|
: data
|
|
147
147
|
),
|
|
148
148
|
componentsRegistry: {},
|
|
@@ -197,7 +197,7 @@ export default DitoComponent.component('DitoSchema', {
|
|
|
197
197
|
const { defaultTab } = tab
|
|
198
198
|
if (
|
|
199
199
|
isFunction(defaultTab)
|
|
200
|
-
? defaultTab
|
|
200
|
+
? defaultTab(this.context)
|
|
201
201
|
: defaultTab
|
|
202
202
|
) {
|
|
203
203
|
return tab
|
|
@@ -214,6 +214,11 @@ export default DitoComponent.component('DitoSchema', {
|
|
|
214
214
|
return this.schema?.clipboard
|
|
215
215
|
},
|
|
216
216
|
|
|
217
|
+
parentData() {
|
|
218
|
+
const data = getParentItem(this.rootData, this.dataPath, false)
|
|
219
|
+
return data !== this.data ? data : null
|
|
220
|
+
},
|
|
221
|
+
|
|
217
222
|
processedData() {
|
|
218
223
|
return this.processData({ target: 'server', schemaOnly: true })
|
|
219
224
|
},
|
|
@@ -235,6 +240,10 @@ export default DitoComponent.component('DitoSchema', {
|
|
|
235
240
|
return this.data
|
|
236
241
|
},
|
|
237
242
|
|
|
243
|
+
parentItem() {
|
|
244
|
+
return this.parentData
|
|
245
|
+
},
|
|
246
|
+
|
|
238
247
|
rootItem() {
|
|
239
248
|
return this.rootData
|
|
240
249
|
},
|
|
@@ -247,10 +256,6 @@ export default DitoComponent.component('DitoSchema', {
|
|
|
247
256
|
return this.clipboardData
|
|
248
257
|
},
|
|
249
258
|
|
|
250
|
-
parentItem() {
|
|
251
|
-
return getParentItem(this.rootData, this.dataPath, false)
|
|
252
|
-
},
|
|
253
|
-
|
|
254
259
|
formLabel() {
|
|
255
260
|
return this.getLabel(
|
|
256
261
|
this.getItemFormSchema(this.sourceSchema, this.data, this.context)
|
|
@@ -10,6 +10,7 @@ DitoSchema.dito-schema-inlined(
|
|
|
10
10
|
:disabled="disabled"
|
|
11
11
|
:collapsed="collapsed"
|
|
12
12
|
:collapsible="collapsible"
|
|
13
|
+
:generateLabels="!isCompact"
|
|
13
14
|
:class="{ 'dito-schema-compact': isCompact }"
|
|
14
15
|
)
|
|
15
16
|
//- Render dito-edit-buttons for inlined schemas separately from all
|
|
@@ -72,11 +72,12 @@
|
|
|
72
72
|
:store="store"
|
|
73
73
|
:disabled="disabled"
|
|
74
74
|
)
|
|
75
|
-
|
|
75
|
+
DitoDraggable(
|
|
76
76
|
v-if="childrenSchema"
|
|
77
77
|
v-show="opened"
|
|
78
78
|
:modelValue="updateOrder(childrenSchema, childrenList)"
|
|
79
|
-
:options="getSortableOptions(
|
|
79
|
+
:options="getSortableOptions(true)"
|
|
80
|
+
:draggable="childrenDraggable"
|
|
80
81
|
@update:modelValue="value => (childrenList = value)"
|
|
81
82
|
)
|
|
82
83
|
DitoTreeItem(
|
package/src/components/index.js
CHANGED
|
@@ -30,4 +30,5 @@ export { default as DitoPagination } from './DitoPagination.vue'
|
|
|
30
30
|
export { default as DitoTreeItem } from './DitoTreeItem.vue'
|
|
31
31
|
export { default as DitoTableHead } from './DitoTableHead.vue'
|
|
32
32
|
export { default as DitoTableCell } from './DitoTableCell.vue'
|
|
33
|
+
export { default as DitoDraggable } from './DitoDraggable.vue'
|
|
33
34
|
export { default as DitoVNode } from './DitoVNode.vue'
|
package/src/mixins/DataMixin.js
CHANGED
|
@@ -38,7 +38,7 @@ export default {
|
|
|
38
38
|
// If the data callback provided a dependency function when it was called,
|
|
39
39
|
// cal it in every call of `handleDataSchema()` to force Vue to keep track
|
|
40
40
|
// of the async dependencies.
|
|
41
|
-
asyncEntry.dependencyFunction?.
|
|
41
|
+
asyncEntry.dependencyFunction?.(this.context)
|
|
42
42
|
|
|
43
43
|
if (asyncEntry.resolveCounter > 0) {
|
|
44
44
|
// If the data was resolved already, return it and clear the value once
|
|
@@ -59,7 +59,7 @@ export default {
|
|
|
59
59
|
data = null
|
|
60
60
|
} else if (data) {
|
|
61
61
|
if (isFunction(data)) {
|
|
62
|
-
const result = data
|
|
62
|
+
const result = data(this.context)
|
|
63
63
|
// If the result of the data function is another function, then the
|
|
64
64
|
// first data function is there to track dependencies and the real
|
|
65
65
|
// data loading happens in the function that it returned. Keep track
|
|
@@ -68,7 +68,7 @@ export default {
|
|
|
68
68
|
// the function that it returned once to get the actual data:
|
|
69
69
|
if (isFunction(result)) {
|
|
70
70
|
asyncEntry.dependencyFunction = data
|
|
71
|
-
data = result
|
|
71
|
+
data = result(this.context)
|
|
72
72
|
} else {
|
|
73
73
|
data = result
|
|
74
74
|
}
|
package/src/mixins/DitoMixin.js
CHANGED
|
@@ -213,7 +213,7 @@ export default {
|
|
|
213
213
|
if (value === undefined && def !== undefined) {
|
|
214
214
|
if (callback && isFunction(def) && !isMatchingType(types, def)) {
|
|
215
215
|
// Support `default()` functions for any type except `Function`:
|
|
216
|
-
def = def.call(this
|
|
216
|
+
def = def.call(this)
|
|
217
217
|
}
|
|
218
218
|
return def
|
|
219
219
|
}
|
|
@@ -224,7 +224,7 @@ export default {
|
|
|
224
224
|
// Any schema value handled through `getSchemaValue()` can provide
|
|
225
225
|
// a function that's resolved when the value is evaluated:
|
|
226
226
|
if (callback && isFunction(value)) {
|
|
227
|
-
value = value
|
|
227
|
+
value = value(this.context)
|
|
228
228
|
}
|
|
229
229
|
// Now finally see if we can convert to the expect types.
|
|
230
230
|
if (types && value != null && !isMatchingType(types, value)) {
|
|
@@ -265,14 +265,27 @@ export default {
|
|
|
265
265
|
},
|
|
266
266
|
|
|
267
267
|
shouldRender(schema = null) {
|
|
268
|
-
return (
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
268
|
+
return this.getSchemaValue('if', {
|
|
269
|
+
type: Boolean,
|
|
270
|
+
default: true,
|
|
271
|
+
schema
|
|
272
|
+
})
|
|
273
|
+
},
|
|
274
|
+
|
|
275
|
+
shouldShow(schema = null) {
|
|
276
|
+
return this.getSchemaValue('visible', {
|
|
277
|
+
type: Boolean,
|
|
278
|
+
default: true,
|
|
279
|
+
schema
|
|
280
|
+
})
|
|
281
|
+
},
|
|
282
|
+
|
|
283
|
+
shouldDisable(schema = null) {
|
|
284
|
+
return this.getSchemaValue('disabled', {
|
|
285
|
+
type: Boolean,
|
|
286
|
+
default: false,
|
|
287
|
+
schema
|
|
288
|
+
})
|
|
276
289
|
},
|
|
277
290
|
|
|
278
291
|
getResourcePath(resource) {
|
package/src/mixins/RouteMixin.js
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import ItemMixin from './ItemMixin.js'
|
|
2
|
-
import { UseSortable } from '@vueuse/integrations/useSortable/component'
|
|
3
2
|
|
|
4
3
|
// @vue/component
|
|
5
4
|
export default {
|
|
6
5
|
mixins: [ItemMixin],
|
|
7
|
-
components: { UseSortable },
|
|
8
6
|
|
|
9
7
|
data() {
|
|
10
8
|
return {
|
|
@@ -13,17 +11,15 @@ export default {
|
|
|
13
11
|
},
|
|
14
12
|
|
|
15
13
|
methods: {
|
|
16
|
-
getSortableOptions(
|
|
14
|
+
getSortableOptions(forceFallback = false) {
|
|
17
15
|
return {
|
|
18
16
|
animation: 150,
|
|
19
|
-
// TODO: This is broken in VueSortable, always enable it for now.
|
|
20
|
-
// disabled: !draggable,
|
|
21
17
|
handle: '.dito-button-drag',
|
|
22
18
|
dragClass: 'dito-sortable-active',
|
|
23
19
|
chosenClass: 'dito-sortable-chosen',
|
|
24
20
|
ghostClass: 'dito-sortable-ghost',
|
|
25
21
|
fallbackClass: 'dito-sortable-fallback',
|
|
26
|
-
forceFallback
|
|
22
|
+
forceFallback,
|
|
27
23
|
onStart: this.onStartDrag,
|
|
28
24
|
onEnd: this.onEndDrag
|
|
29
25
|
}
|
|
@@ -11,7 +11,6 @@ import {
|
|
|
11
11
|
hasFormSchema,
|
|
12
12
|
getFormSchemas,
|
|
13
13
|
getViewSchema,
|
|
14
|
-
hasLabels,
|
|
15
14
|
isCompact,
|
|
16
15
|
isInlined,
|
|
17
16
|
isObjectSource,
|
|
@@ -249,10 +248,6 @@ export default {
|
|
|
249
248
|
return getButtonSchemas(this.schema.buttons)
|
|
250
249
|
},
|
|
251
250
|
|
|
252
|
-
hasLabels() {
|
|
253
|
-
return this.forms.some(hasLabels)
|
|
254
|
-
},
|
|
255
|
-
|
|
256
251
|
isCompact() {
|
|
257
252
|
return this.forms.every(isCompact)
|
|
258
253
|
},
|
package/src/mixins/TypeMixin.js
CHANGED
|
@@ -3,7 +3,7 @@ import ValidationMixin from './ValidationMixin.js'
|
|
|
3
3
|
import { getSchemaAccessor } from '../utils/accessor.js'
|
|
4
4
|
import { computeValue } from '../utils/schema.js'
|
|
5
5
|
import { getItem, getParentItem } from '../utils/data.js'
|
|
6
|
-
import { isString, asArray } from '@ditojs/utils'
|
|
6
|
+
import { isString, asArray, camelize } from '@ditojs/utils'
|
|
7
7
|
|
|
8
8
|
// @vue/component
|
|
9
9
|
export default {
|
|
@@ -71,14 +71,32 @@ export default {
|
|
|
71
71
|
}
|
|
72
72
|
},
|
|
73
73
|
|
|
74
|
+
parentData() {
|
|
75
|
+
const data = getParentItem(this.rootData, this.dataPath, this.nested)
|
|
76
|
+
return data !== this.data ? data : null
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
processedData() {
|
|
80
|
+
// We can only get the processed data through the schemaComponent, but
|
|
81
|
+
// that's not necessarily the item represented by this component.
|
|
82
|
+
// Solution: Find the relative path and the processed sub-item from there:
|
|
83
|
+
const { schemaComponent } = this
|
|
84
|
+
return getItem(
|
|
85
|
+
schemaComponent.processedData,
|
|
86
|
+
// Get the dataPath relative to the schemaComponent's data:
|
|
87
|
+
this.dataPath.slice(schemaComponent.dataPath.length),
|
|
88
|
+
this.nested
|
|
89
|
+
)
|
|
90
|
+
},
|
|
91
|
+
|
|
74
92
|
// The following computed properties are similar to `DitoContext`
|
|
75
93
|
// properties, so that we can access these on `this` as well:
|
|
76
94
|
item() {
|
|
77
|
-
return
|
|
95
|
+
return this.data
|
|
78
96
|
},
|
|
79
97
|
|
|
80
98
|
parentItem() {
|
|
81
|
-
return
|
|
99
|
+
return this.parentData
|
|
82
100
|
},
|
|
83
101
|
|
|
84
102
|
rootItem() {
|
|
@@ -86,16 +104,7 @@ export default {
|
|
|
86
104
|
},
|
|
87
105
|
|
|
88
106
|
processedItem() {
|
|
89
|
-
|
|
90
|
-
// that's not necessarily the item represented by this component.
|
|
91
|
-
// Solution: Find the relative path and the processed sub-item from there:
|
|
92
|
-
const { schemaComponent } = this
|
|
93
|
-
return getItem(
|
|
94
|
-
schemaComponent.processedItem,
|
|
95
|
-
// Get the dataPath relative to the schemaComponent's data:
|
|
96
|
-
this.dataPath.slice(schemaComponent.dataPath.length),
|
|
97
|
-
this.nested
|
|
98
|
-
)
|
|
107
|
+
return this.processedData
|
|
99
108
|
},
|
|
100
109
|
|
|
101
110
|
label: getSchemaAccessor('label', {
|
|
@@ -120,7 +129,7 @@ export default {
|
|
|
120
129
|
}
|
|
121
130
|
}),
|
|
122
131
|
|
|
123
|
-
// TODO: Rename to `excluded` for consistent naming
|
|
132
|
+
// TODO: Rename to `excluded` for consistent naming?
|
|
124
133
|
exclude: getSchemaAccessor('exclude', {
|
|
125
134
|
type: Boolean,
|
|
126
135
|
default: false
|
|
@@ -156,10 +165,18 @@ export default {
|
|
|
156
165
|
type: String
|
|
157
166
|
}),
|
|
158
167
|
|
|
159
|
-
// @overridable
|
|
160
168
|
events() {
|
|
161
|
-
const
|
|
162
|
-
|
|
169
|
+
const events = this.getEvents()
|
|
170
|
+
// Register callbacks for all provides non-recognized events,
|
|
171
|
+
// assuming they are native events.
|
|
172
|
+
// TODO: Move to vue3-style `on[A-Z]` event handlers naming that aren't
|
|
173
|
+
// namespaced in `schema.events` once the transition is complete.
|
|
174
|
+
for (const event of Object.keys(this.schema.events || {})) {
|
|
175
|
+
events[`on${camelize(event, true)}`] ??= () => {
|
|
176
|
+
this.emitEvent(event)
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return events
|
|
163
180
|
},
|
|
164
181
|
|
|
165
182
|
attributes() {
|
|
@@ -224,6 +241,12 @@ export default {
|
|
|
224
241
|
}
|
|
225
242
|
},
|
|
226
243
|
|
|
244
|
+
// @overridable
|
|
245
|
+
getEvents() {
|
|
246
|
+
const { onFocus, onBlur, onInput, onChange } = this
|
|
247
|
+
return { onFocus, onBlur, onInput, onChange }
|
|
248
|
+
},
|
|
249
|
+
|
|
227
250
|
// @overridable
|
|
228
251
|
getValidations() {
|
|
229
252
|
return null
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
@import '../styles/_imports';
|
|
2
|
+
|
|
1
3
|
ul.dito-pulldown {
|
|
2
4
|
display: none;
|
|
3
5
|
position: absolute;
|
|
@@ -5,6 +7,7 @@ ul.dito-pulldown {
|
|
|
5
7
|
z-index: 1000;
|
|
6
8
|
border-radius: $pulldown-radius;
|
|
7
9
|
box-shadow: $shadow-window;
|
|
10
|
+
overflow: hidden;
|
|
8
11
|
|
|
9
12
|
&.dito-open {
|
|
10
13
|
display: block;
|
|
@@ -15,25 +18,19 @@ ul.dito-pulldown {
|
|
|
15
18
|
|
|
16
19
|
a {
|
|
17
20
|
display: block;
|
|
18
|
-
text-align: center;
|
|
19
21
|
padding: $pulldown-padding;
|
|
20
22
|
line-height: 1;
|
|
21
23
|
background: $button-color;
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
&.dito-disabled {
|
|
26
|
+
color: $color-disabled;
|
|
27
|
+
cursor: default;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
&:not(.dito-disabled):hover {
|
|
24
31
|
background: $color-active;
|
|
25
32
|
color: $color-white;
|
|
26
33
|
}
|
|
27
34
|
}
|
|
28
|
-
|
|
29
|
-
&:first-child a {
|
|
30
|
-
border-top-left-radius: $pulldown-radius;
|
|
31
|
-
border-top-right-radius: $pulldown-radius;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
&:last-child a {
|
|
35
|
-
border-bottom-left-radius: $pulldown-radius;
|
|
36
|
-
border-bottom-right-radius: $pulldown-radius;
|
|
37
|
-
}
|
|
38
35
|
}
|
|
39
36
|
}
|