@ditojs/admin 3.2.7 → 3.3.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.
- package/dist/dito-admin.css +1 -1
- package/dist/dito-admin.es.js +6011 -5826
- package/dist/dito-admin.umd.js +3 -7
- package/package.json +18 -17
- package/src/DitoAdmin.js +44 -24
- package/src/DitoContext.js +28 -2
- package/src/DitoTypeComponent.js +1 -0
- package/src/appState.js +6 -3
- package/src/components/DitoAccount.vue +35 -27
- package/src/components/DitoAffixes.vue +9 -2
- package/src/components/DitoClipboard.vue +59 -93
- package/src/components/DitoConfirmMessage.vue +18 -0
- package/src/components/DitoContainer.vue +56 -18
- package/src/components/DitoCreateButton.vue +36 -84
- package/src/components/DitoDialog.vue +20 -15
- package/src/components/DitoDragHandle.vue +44 -0
- package/src/components/DitoDraggable.vue +43 -16
- package/src/components/DitoEditButtons.vue +48 -24
- package/src/components/DitoErrors.vue +9 -56
- package/src/components/DitoForm.vue +82 -42
- package/src/components/DitoInputAffixes.vue +50 -0
- package/src/components/DitoLabel.vue +1 -15
- package/src/components/DitoMenu.vue +45 -52
- package/src/components/DitoNotifications.vue +38 -14
- package/src/components/DitoOptionList.vue +81 -0
- package/src/components/DitoOptionsEditButtons.vue +57 -0
- package/src/components/DitoPagination.vue +1 -8
- package/src/components/DitoPane.vue +51 -39
- package/src/components/DitoPanel.vue +12 -26
- package/src/components/DitoPanels.vue +11 -5
- package/src/components/DitoResizeHandle.vue +47 -0
- package/src/components/DitoRoot.vue +113 -320
- package/src/components/DitoSchema.vue +72 -63
- package/src/components/DitoSchemaInlined.vue +8 -9
- package/src/components/DitoScopes.vue +14 -18
- package/src/components/DitoSidebar.vue +4 -29
- package/src/components/DitoSourceItem.vue +114 -0
- package/src/components/DitoTableCell.vue +4 -0
- package/src/components/DitoTableHead.vue +15 -17
- package/src/components/DitoTabs.vue +25 -0
- package/src/components/DitoTrail.vue +25 -25
- package/src/components/DitoTreeItem.vue +102 -141
- package/src/components/DitoUploadFile.vue +5 -2
- package/src/components/DitoView.vue +33 -24
- package/src/index.js +4 -1
- package/src/mixins/DitoMixin.js +77 -110
- package/src/mixins/DomMixin.js +12 -14
- package/src/mixins/EmitterMixin.js +3 -2
- package/src/mixins/ItemMixin.js +38 -94
- package/src/mixins/OptionsMixin.js +38 -25
- package/src/mixins/ResourceMixin.js +182 -111
- package/src/mixins/RouteMixin.js +61 -44
- package/src/mixins/SchemaParentMixin.js +4 -1
- package/src/mixins/SourceMixin.js +118 -100
- package/src/mixins/TypeMixin.js +42 -40
- package/src/mixins/ValidationMixin.js +16 -4
- package/src/mixins/ValidatorMixin.js +1 -1
- package/src/styles/_settings.scss +4 -0
- package/src/styles/_tippy.scss +0 -11
- package/src/styles/style.scss +0 -1
- package/src/types/DitoTypeButton.vue +11 -14
- package/src/types/DitoTypeCheckboxes.vue +35 -17
- package/src/types/DitoTypeCode.vue +19 -41
- package/src/types/DitoTypeColor.vue +67 -19
- package/src/types/DitoTypeDate.vue +11 -14
- package/src/types/DitoTypeList.vue +50 -62
- package/src/types/DitoTypeMarkup.vue +41 -54
- package/src/types/DitoTypeMultiselect.vue +82 -52
- package/src/types/DitoTypeNumber.vue +12 -15
- package/src/types/DitoTypeObject.vue +4 -38
- package/src/types/DitoTypeRadio.vue +19 -6
- package/src/types/DitoTypeSection.vue +23 -9
- package/src/types/DitoTypeSelect.vue +39 -23
- package/src/types/DitoTypeSlider.vue +9 -1
- package/src/types/DitoTypeSwitch.vue +1 -1
- package/src/types/DitoTypeText.vue +11 -14
- package/src/types/DitoTypeTreeList.vue +46 -8
- package/src/types/DitoTypeUpload.vue +190 -67
- package/src/utils/DataModel.js +368 -146
- package/src/utils/FileDropTargets.js +97 -0
- package/src/utils/ItemStores.js +31 -0
- package/src/utils/ListQuery.js +115 -0
- package/src/utils/LoadingTracker.js +76 -0
- package/src/utils/SchemaGraph.js +3 -2
- package/src/utils/Session.js +151 -0
- package/src/utils/ViewRegistry.js +85 -0
- package/src/utils/accessor.js +12 -4
- package/src/utils/affixes.js +33 -0
- package/src/utils/changeOnceEdited.js +33 -0
- package/src/utils/clipboard.js +55 -0
- package/src/utils/data.js +10 -5
- package/src/utils/dialogs.js +59 -0
- package/src/utils/dragResize.js +61 -0
- package/src/utils/filter.js +36 -2
- package/src/utils/html.js +9 -0
- package/src/utils/list.js +10 -0
- package/src/utils/options.js +4 -0
- package/src/utils/registration.js +18 -0
- package/src/utils/request.js +108 -13
- package/src/utils/route.js +6 -17
- package/src/utils/schema/data.js +24 -2
- package/src/utils/schema/events.js +19 -0
- package/src/utils/schema/item.js +114 -0
- package/src/utils/schema/lookup.js +39 -14
- package/src/utils/schema/setup.js +5 -5
- package/src/utils/schema/validation.js +16 -2
- package/src/utils/uid.js +105 -8
- package/src/validators/_decimals.js +16 -5
- package/types/index.d.ts +168 -41
- package/src/mixins/LoadingMixin.js +0 -23
- package/src/mixins/PulldownMixin.js +0 -72
- package/src/styles/_pulldown.scss +0 -38
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
<template lang="pug">
|
|
2
|
+
//- The list of the options of an options component that shows all of them at
|
|
3
|
+
//- once, e.g. radio buttons and checkboxes. Grouped options, see
|
|
4
|
+
//- `schema.groupBy`, are listed in a fieldset per group. The `option` slot
|
|
5
|
+
//- renders each option, and receives `isFirstOption` so that the component can
|
|
6
|
+
//- reference the input to focus, see `TypeMixin.getFocusElement()`.
|
|
7
|
+
ul.dito-option-list(:class="layoutClass")
|
|
8
|
+
template(
|
|
9
|
+
v-if="isGrouped"
|
|
10
|
+
)
|
|
11
|
+
li.dito-option-list__group(
|
|
12
|
+
v-for="group in options"
|
|
13
|
+
:key="group.label"
|
|
14
|
+
)
|
|
15
|
+
fieldset.dito-option-list__fieldset
|
|
16
|
+
legend.dito-option-list__legend {{ group.label }}
|
|
17
|
+
ul.dito-option-list__options(:class="layoutClass")
|
|
18
|
+
li.dito-option-list__option(
|
|
19
|
+
v-for="option in group.options"
|
|
20
|
+
)
|
|
21
|
+
slot(
|
|
22
|
+
name="option"
|
|
23
|
+
:option="option"
|
|
24
|
+
:isFirstOption="option === firstOption"
|
|
25
|
+
)
|
|
26
|
+
template(
|
|
27
|
+
v-else
|
|
28
|
+
)
|
|
29
|
+
li.dito-option-list__option(
|
|
30
|
+
v-for="option in options"
|
|
31
|
+
)
|
|
32
|
+
slot(
|
|
33
|
+
name="option"
|
|
34
|
+
:option="option"
|
|
35
|
+
:isFirstOption="option === firstOption"
|
|
36
|
+
)
|
|
37
|
+
</template>
|
|
38
|
+
|
|
39
|
+
<script>
|
|
40
|
+
import DitoComponent from '../DitoComponent.js'
|
|
41
|
+
|
|
42
|
+
// @vue/component
|
|
43
|
+
export default DitoComponent.component('DitoOptionList', {
|
|
44
|
+
props: {
|
|
45
|
+
// The options, or with `isGrouped` their groups, each with `label` and
|
|
46
|
+
// `options`, see `OptionsMixin.groupOptions()`.
|
|
47
|
+
options: { type: Array, required: true },
|
|
48
|
+
isGrouped: { type: Boolean, default: false },
|
|
49
|
+
layout: { type: String, default: null }
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
computed: {
|
|
53
|
+
layoutClass() {
|
|
54
|
+
return `dito-layout--${this.layout || 'vertical'}`
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
firstOption() {
|
|
58
|
+
const [firstEntry] = this.options
|
|
59
|
+
return this.isGrouped ? firstEntry?.options[0] : firstEntry
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
</script>
|
|
64
|
+
|
|
65
|
+
<style lang="scss">
|
|
66
|
+
@import '../styles/_imports';
|
|
67
|
+
|
|
68
|
+
.dito-option-list {
|
|
69
|
+
&__fieldset {
|
|
70
|
+
margin: 0;
|
|
71
|
+
padding: 0;
|
|
72
|
+
border: 0;
|
|
73
|
+
min-width: 0;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
&__legend {
|
|
77
|
+
padding: 0;
|
|
78
|
+
font-weight: bold;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
</style>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<template lang="pug">
|
|
2
|
+
//- The edit button of an option of an editable options component, which
|
|
3
|
+
//- navigates to the form of the option in the view of `schema.view`. It's never
|
|
4
|
+
//- disabled, even if the component is disabled. The props come from the
|
|
5
|
+
//- options component, which renders it only when it's editable.
|
|
6
|
+
DitoEditButtons.dito-options-edit-buttons(
|
|
7
|
+
:schema="schema"
|
|
8
|
+
:dataPath="dataPath"
|
|
9
|
+
:data="data"
|
|
10
|
+
:meta="meta"
|
|
11
|
+
:store="store"
|
|
12
|
+
:disabled="false"
|
|
13
|
+
editable
|
|
14
|
+
:editPath="editPath"
|
|
15
|
+
)
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
<script>
|
|
19
|
+
import DitoComponent from '../DitoComponent.js'
|
|
20
|
+
import DitoEditButtons from './DitoEditButtons.vue'
|
|
21
|
+
import { getViewEditPath } from '../utils/schema/lookup.js'
|
|
22
|
+
|
|
23
|
+
// @vue/component
|
|
24
|
+
export default DitoComponent.component('DitoOptionsEditButtons', {
|
|
25
|
+
components: { DitoEditButtons },
|
|
26
|
+
|
|
27
|
+
props: {
|
|
28
|
+
schema: { type: Object, required: true },
|
|
29
|
+
dataPath: { type: String, required: true },
|
|
30
|
+
data: { type: [Object, Array], default: null },
|
|
31
|
+
meta: { type: Object, required: true },
|
|
32
|
+
store: { type: Object, required: true },
|
|
33
|
+
// The context of the options component, to resolve `schema.view`. Not
|
|
34
|
+
// named `context`, which is the component's own context, see DitoMixin.
|
|
35
|
+
parentContext: { type: Object, required: true },
|
|
36
|
+
// The value of the option to edit, e.g. its id.
|
|
37
|
+
optionValue: { type: null, default: null }
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
computed: {
|
|
41
|
+
editPath() {
|
|
42
|
+
const { schema, optionValue, parentContext } = this
|
|
43
|
+
return optionValue != null
|
|
44
|
+
? getViewEditPath(schema, optionValue, parentContext)
|
|
45
|
+
: null
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
</script>
|
|
50
|
+
|
|
51
|
+
<style lang="scss">
|
|
52
|
+
@import '../styles/_imports';
|
|
53
|
+
|
|
54
|
+
.dito-options-edit-buttons {
|
|
55
|
+
margin-left: $form-spacing-half;
|
|
56
|
+
}
|
|
57
|
+
</style>
|
|
@@ -27,14 +27,7 @@ export default DitoComponent.component('DitoPagination', {
|
|
|
27
27
|
},
|
|
28
28
|
|
|
29
29
|
set(page) {
|
|
30
|
-
|
|
31
|
-
this.$router.push(
|
|
32
|
-
this.getQueryLink({
|
|
33
|
-
...this.query,
|
|
34
|
-
page: page - 1
|
|
35
|
-
})
|
|
36
|
-
)
|
|
37
|
-
}
|
|
30
|
+
this.sourceComponent.listQuery.update({ page: page - 1 })
|
|
38
31
|
}
|
|
39
32
|
}
|
|
40
33
|
}
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
v-if="['before', 'both'].includes(schema.break)"
|
|
24
24
|
)
|
|
25
25
|
DitoContainer(
|
|
26
|
-
v-if="
|
|
26
|
+
v-if="shouldRenderComponentByIndex[index]"
|
|
27
27
|
ref="containers"
|
|
28
28
|
:key="nestedDataPath"
|
|
29
29
|
:data-index="index"
|
|
@@ -38,7 +38,6 @@
|
|
|
38
38
|
:compact="compact"
|
|
39
39
|
:generateLabels="generateLabels"
|
|
40
40
|
:verticalLabels="isInLabeledRow(index)"
|
|
41
|
-
:accumulatedBasis="accumulatedBasis"
|
|
42
41
|
)
|
|
43
42
|
span.dito-pane__break(
|
|
44
43
|
v-if="['after', 'both'].includes(schema.break)"
|
|
@@ -50,7 +49,8 @@ import DitoComponent from '../DitoComponent.js'
|
|
|
50
49
|
import DitoContext from '../DitoContext.js'
|
|
51
50
|
import ContextMixin from '../mixins/ContextMixin.js'
|
|
52
51
|
import { appendDataPath } from '../utils/data.js'
|
|
53
|
-
import {
|
|
52
|
+
import { trackRegistration } from '../utils/registration.js'
|
|
53
|
+
import { hasLabel, isNested } from '../utils/schema/structure.js'
|
|
54
54
|
import { shouldRenderSchema } from '../utils/schema/data.js'
|
|
55
55
|
|
|
56
56
|
// @vue/component
|
|
@@ -74,8 +74,7 @@ export default DitoComponent.component('DitoPane', {
|
|
|
74
74
|
padding: { type: String, default: null },
|
|
75
75
|
disabled: { type: Boolean, default: false },
|
|
76
76
|
compact: { type: Boolean, default: false },
|
|
77
|
-
generateLabels: { type: Boolean, default: false }
|
|
78
|
-
accumulatedBasis: { type: Number, default: null }
|
|
77
|
+
generateLabels: { type: Boolean, default: false }
|
|
79
78
|
},
|
|
80
79
|
|
|
81
80
|
data() {
|
|
@@ -102,6 +101,19 @@ export default DitoComponent.component('DitoPane', {
|
|
|
102
101
|
return this.tab ? this : this.$tabComponent()
|
|
103
102
|
},
|
|
104
103
|
|
|
104
|
+
// Describes the tab of tab panes with data for the entries of the panels
|
|
105
|
+
// of their components, see `getAllPanelEntries()`. Panes in tabs that
|
|
106
|
+
// aren't tab panes themselves are reached through `tabComponent`.
|
|
107
|
+
panelTab() {
|
|
108
|
+
const { tab, schemaComponent } = this
|
|
109
|
+
return tab
|
|
110
|
+
? {
|
|
111
|
+
tabName: tab,
|
|
112
|
+
isTabSelected: () => schemaComponent.isTabSelected(tab)
|
|
113
|
+
}
|
|
114
|
+
: null
|
|
115
|
+
},
|
|
116
|
+
|
|
105
117
|
componentPath() {
|
|
106
118
|
// Tabs add their name, as they don't appear in data paths.
|
|
107
119
|
const { componentPath } = this.parentComponent
|
|
@@ -145,7 +157,10 @@ export default DitoComponent.component('DitoPane', {
|
|
|
145
157
|
dataPath,
|
|
146
158
|
nestedDataPath,
|
|
147
159
|
nested,
|
|
148
|
-
store: this.getChildStore(name)
|
|
160
|
+
store: this.getChildStore(name),
|
|
161
|
+
// The same as `DitoContainer.hasLabel`, also for type components
|
|
162
|
+
// that render their own label, e.g. sections.
|
|
163
|
+
hasLabel: hasLabel(schema, this.generateLabels)
|
|
149
164
|
}
|
|
150
165
|
}
|
|
151
166
|
)
|
|
@@ -155,8 +170,22 @@ export default DitoComponent.component('DitoPane', {
|
|
|
155
170
|
return this.single && this.componentSchemas.length === 1
|
|
156
171
|
},
|
|
157
172
|
|
|
173
|
+
shouldRenderComponentByIndex() {
|
|
174
|
+
return this.componentSchemas.map(({ schema, nested, dataPath }) =>
|
|
175
|
+
this.shouldRenderComponent(schema, nested, dataPath)
|
|
176
|
+
)
|
|
177
|
+
},
|
|
178
|
+
|
|
179
|
+
renderedPositions() {
|
|
180
|
+
// Ignore the positions of containers that aren't rendered anymore, as
|
|
181
|
+
// their removal doesn't necessarily resize the pane, see `onResizePane()`
|
|
182
|
+
return this.positions.map((position, index) =>
|
|
183
|
+
this.shouldRenderComponentByIndex[index] ? position : null
|
|
184
|
+
)
|
|
185
|
+
},
|
|
186
|
+
|
|
158
187
|
verticalLabelsByIndices() {
|
|
159
|
-
const
|
|
188
|
+
const positions = this.renderedPositions
|
|
160
189
|
|
|
161
190
|
const isLastInRow = index => (
|
|
162
191
|
positions[index] && (
|
|
@@ -190,17 +219,14 @@ export default DitoComponent.component('DitoPane', {
|
|
|
190
219
|
for (const row of rows) {
|
|
191
220
|
let hasLabelsInRow = false
|
|
192
221
|
for (const index of row) {
|
|
193
|
-
|
|
222
|
+
// Labels in compact schemas are displayed next to their components,
|
|
223
|
+
// so only count labels of containers that are higher than one line.
|
|
224
|
+
// TODO: Handle nested schemas, e.g. 'section' or 'object' and
|
|
225
|
+
// detect labels there too.
|
|
194
226
|
if (
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
position.node
|
|
198
|
-
.closest('.dito-container')
|
|
199
|
-
.matches('.dito-container--label-vertical')
|
|
200
|
-
)
|
|
227
|
+
positions[index]?.height > 2 &&
|
|
228
|
+
this.componentSchemas[index].hasLabel
|
|
201
229
|
) {
|
|
202
|
-
// TODO: Handle nested schemas, e.g. 'section' or 'object' and
|
|
203
|
-
// detect labels there too.
|
|
204
230
|
hasLabelsInRow = true
|
|
205
231
|
break
|
|
206
232
|
}
|
|
@@ -217,21 +243,17 @@ export default DitoComponent.component('DitoPane', {
|
|
|
217
243
|
watch: {
|
|
218
244
|
'componentSchemas.length'(length) {
|
|
219
245
|
this.positions.length = length
|
|
220
|
-
},
|
|
221
|
-
|
|
222
|
-
'componentPath'(componentPath, oldComponentPath) {
|
|
223
|
-
// Component paths change when list items move, see `_registerEntry()`.
|
|
224
|
-
this._register(false, oldComponentPath)
|
|
225
|
-
this._register(true, componentPath)
|
|
226
246
|
}
|
|
227
247
|
},
|
|
228
248
|
|
|
229
249
|
created() {
|
|
230
|
-
this.
|
|
250
|
+
this._unregister = trackRegistration(this, (add, componentPath) =>
|
|
251
|
+
this.schemaComponent._registerPane(this, add, componentPath)
|
|
252
|
+
)
|
|
231
253
|
},
|
|
232
254
|
|
|
233
255
|
unmounted() {
|
|
234
|
-
this.
|
|
256
|
+
this._unregister()
|
|
235
257
|
},
|
|
236
258
|
|
|
237
259
|
methods: {
|
|
@@ -251,10 +273,6 @@ export default DitoComponent.component('DitoPane', {
|
|
|
251
273
|
)
|
|
252
274
|
},
|
|
253
275
|
|
|
254
|
-
_register(add, componentPath = this.componentPath) {
|
|
255
|
-
this.schemaComponent._registerPane(this, add, componentPath)
|
|
256
|
-
},
|
|
257
|
-
|
|
258
276
|
focus() {
|
|
259
277
|
if (this.tab) {
|
|
260
278
|
return this.$router.push({ hash: `#${this.tab}` })
|
|
@@ -278,8 +296,7 @@ export default DitoComponent.component('DitoPane', {
|
|
|
278
296
|
? null
|
|
279
297
|
: {
|
|
280
298
|
top: bounds.y,
|
|
281
|
-
height: height / fontSize
|
|
282
|
-
node
|
|
299
|
+
height: height / fontSize
|
|
283
300
|
}
|
|
284
301
|
}
|
|
285
302
|
})
|
|
@@ -335,8 +352,10 @@ export default DitoComponent.component('DitoPane', {
|
|
|
335
352
|
margin-top: -$form-spacing-half;
|
|
336
353
|
}
|
|
337
354
|
|
|
338
|
-
// Display a ruler between tabbed components and
|
|
339
|
-
|
|
355
|
+
// Display a ruler between the tabbed components and the main components.
|
|
356
|
+
// `dito-pane__tab` and `dito-pane__main` are set on the panes themselves,
|
|
357
|
+
// see `DitoSchema`:
|
|
358
|
+
&#{$self}__tab + #{$self}__main {
|
|
340
359
|
&::before {
|
|
341
360
|
// Use a pseudo element to display a ruler with proper margins
|
|
342
361
|
display: block;
|
|
@@ -348,13 +367,6 @@ export default DitoComponent.component('DitoPane', {
|
|
|
348
367
|
padding: $form-spacing-half;
|
|
349
368
|
}
|
|
350
369
|
}
|
|
351
|
-
|
|
352
|
-
// TODO: BEM: Style an element class of this block, e.g. `&__buttons`.
|
|
353
|
-
&__main + .dito-buttons--main {
|
|
354
|
-
// Needed forms with sticky main buttons.
|
|
355
|
-
margin: $content-padding;
|
|
356
|
-
margin-bottom: 0;
|
|
357
|
-
}
|
|
358
370
|
}
|
|
359
371
|
|
|
360
372
|
&--padding-inlined {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
//- Only show panels in tabs when the tabs are also visible.
|
|
3
3
|
component.dito-panel(
|
|
4
4
|
v-if="shouldRenderSchema(panelSchema)"
|
|
5
|
-
v-show="visible && (!
|
|
5
|
+
v-show="visible && (!isTabSelected || isTabSelected())"
|
|
6
6
|
:is="panelTag"
|
|
7
7
|
role="region"
|
|
8
8
|
:aria-label="getLabel(schema)"
|
|
@@ -51,6 +51,7 @@ import ContextMixin from '../mixins/ContextMixin.js'
|
|
|
51
51
|
import ValidatorMixin from '../mixins/ValidatorMixin.js'
|
|
52
52
|
import { getButtonSchemas } from '../utils/schema/lookup.js'
|
|
53
53
|
import { getSchemaAccessor } from '../utils/accessor.js'
|
|
54
|
+
import { trackRegistration } from '../utils/registration.js'
|
|
54
55
|
|
|
55
56
|
// @vue/component
|
|
56
57
|
export default DitoComponent.component('DitoPanel', {
|
|
@@ -58,8 +59,7 @@ export default DitoComponent.component('DitoPanel', {
|
|
|
58
59
|
|
|
59
60
|
provide() {
|
|
60
61
|
return {
|
|
61
|
-
$panelComponent: () => this
|
|
62
|
-
$tabComponent: () => this.panelTabComponent
|
|
62
|
+
$panelComponent: () => this
|
|
63
63
|
}
|
|
64
64
|
},
|
|
65
65
|
|
|
@@ -70,7 +70,9 @@ export default DitoComponent.component('DitoPanel', {
|
|
|
70
70
|
meta: { type: Object, required: true },
|
|
71
71
|
store: { type: Object, required: true },
|
|
72
72
|
disabled: { type: Boolean, required: true },
|
|
73
|
-
|
|
73
|
+
// Tells if the tab of the panel's component is selected, for panels of
|
|
74
|
+
// components in tabs, see `getAllPanelEntries()`:
|
|
75
|
+
isTabSelected: { type: Function, default: null },
|
|
74
76
|
// The component path of the panel's entry, see `getAllPanelEntries()`:
|
|
75
77
|
panelComponentPath: { type: String, required: true }
|
|
76
78
|
},
|
|
@@ -108,10 +110,6 @@ export default DitoComponent.component('DitoPanel', {
|
|
|
108
110
|
return this.panelComponentPath
|
|
109
111
|
},
|
|
110
112
|
|
|
111
|
-
tabComponent() {
|
|
112
|
-
return this.panelTabComponent
|
|
113
|
-
},
|
|
114
|
-
|
|
115
113
|
buttonSchemas() {
|
|
116
114
|
return getButtonSchemas(this.schema.buttons)
|
|
117
115
|
},
|
|
@@ -166,16 +164,12 @@ export default DitoComponent.component('DitoPanel', {
|
|
|
166
164
|
})
|
|
167
165
|
},
|
|
168
166
|
|
|
169
|
-
watch: {
|
|
170
|
-
componentPath(componentPath, oldComponentPath) {
|
|
171
|
-
// Component paths change when list items move, see `_registerEntry()`.
|
|
172
|
-
this._register(false, oldComponentPath)
|
|
173
|
-
this._register(true, componentPath)
|
|
174
|
-
}
|
|
175
|
-
},
|
|
176
|
-
|
|
177
167
|
created() {
|
|
178
|
-
|
|
168
|
+
// Register the panels so that other components can find them by their
|
|
169
|
+
// data-path, e.g. in TypeList.onFilterErrors()
|
|
170
|
+
this._unregister = trackRegistration(this, (add, componentPath) =>
|
|
171
|
+
this.schemaComponent._registerPanel(this, add, componentPath)
|
|
172
|
+
)
|
|
179
173
|
// NOTE: This is not the same as `schema.data` handling in DitoSchema,
|
|
180
174
|
// where the data is added to the actual component.
|
|
181
175
|
const { data } = this.schema
|
|
@@ -187,15 +181,7 @@ export default DitoComponent.component('DitoPanel', {
|
|
|
187
181
|
},
|
|
188
182
|
|
|
189
183
|
unmounted() {
|
|
190
|
-
this.
|
|
191
|
-
},
|
|
192
|
-
|
|
193
|
-
methods: {
|
|
194
|
-
_register(add, componentPath = this.componentPath) {
|
|
195
|
-
// Register the panels so that other components can find them by their
|
|
196
|
-
// data-path, e.g. in TypeList.onFilterErrors()
|
|
197
|
-
this.schemaComponent._registerPanel(this, add, componentPath)
|
|
198
|
-
}
|
|
184
|
+
this._unregister()
|
|
199
185
|
}
|
|
200
186
|
})
|
|
201
187
|
</script>
|
|
@@ -3,11 +3,17 @@
|
|
|
3
3
|
v-if="panels.length > 0"
|
|
4
4
|
)
|
|
5
5
|
template(
|
|
6
|
-
v-for
|
|
6
|
+
v-for=`{
|
|
7
|
+
schema,
|
|
8
|
+
dataPath,
|
|
9
|
+
componentPath,
|
|
10
|
+
tabName,
|
|
11
|
+
isTabSelected
|
|
12
|
+
} in panels`
|
|
7
13
|
)
|
|
8
14
|
DitoPanel(
|
|
9
15
|
v-if="shouldRenderSchema(schema)"
|
|
10
|
-
:key="getPanelKey(dataPath,
|
|
16
|
+
:key="getPanelKey(dataPath, tabName)"
|
|
11
17
|
:schema="schema"
|
|
12
18
|
:dataPath="dataPath"
|
|
13
19
|
:panelComponentPath="componentPath"
|
|
@@ -15,7 +21,7 @@
|
|
|
15
21
|
:meta="meta"
|
|
16
22
|
:store="getChildStore(schema.name)"
|
|
17
23
|
:disabled="schema.disabled ?? disabled"
|
|
18
|
-
:
|
|
24
|
+
:isTabSelected="isTabSelected"
|
|
19
25
|
)
|
|
20
26
|
</template>
|
|
21
27
|
|
|
@@ -43,10 +49,10 @@ export default DitoComponent.component('DitoPanels', {
|
|
|
43
49
|
},
|
|
44
50
|
|
|
45
51
|
methods: {
|
|
46
|
-
getPanelKey(dataPath,
|
|
52
|
+
getPanelKey(dataPath, tabName) {
|
|
47
53
|
// Allow separate tabs to use panels of the same name, by
|
|
48
54
|
// prefixing their key with the tab name.
|
|
49
|
-
return
|
|
55
|
+
return tabName ? `${tabName}_${dataPath}` : dataPath
|
|
50
56
|
}
|
|
51
57
|
}
|
|
52
58
|
})
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<template lang="pug">
|
|
2
|
+
//- The handle that resizes the height of an element, by dragging it with the
|
|
3
|
+
//- pointer or with the arrow keys while it is focused, see `dragResize.js`.
|
|
4
|
+
.dito-resize(
|
|
5
|
+
tabindex="0"
|
|
6
|
+
role="separator"
|
|
7
|
+
aria-orientation="horizontal"
|
|
8
|
+
aria-label="Resize"
|
|
9
|
+
@pointerdown.stop.prevent="onPointerDown"
|
|
10
|
+
@keydown="onKeyDown"
|
|
11
|
+
)
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<script>
|
|
15
|
+
import DitoComponent from '../DitoComponent.js'
|
|
16
|
+
import { startDragResize, resizeByArrowKey } from '../utils/dragResize.js'
|
|
17
|
+
|
|
18
|
+
// Emits `resize` with each new height of the element in pixels, which the
|
|
19
|
+
// owner of the element applies.
|
|
20
|
+
// @vue/component
|
|
21
|
+
export default DitoComponent.component('DitoResizeHandle', {
|
|
22
|
+
emits: ['resize'],
|
|
23
|
+
|
|
24
|
+
props: {
|
|
25
|
+
// Returns the element to resize, which is measured at the start of each
|
|
26
|
+
// resize.
|
|
27
|
+
getElement: { type: Function, required: true }
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
methods: {
|
|
31
|
+
onPointerDown(event) {
|
|
32
|
+
startDragResize(event, this.getResizeOptions())
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
onKeyDown(event) {
|
|
36
|
+
resizeByArrowKey(event, this.getResizeOptions())
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
getResizeOptions() {
|
|
40
|
+
return {
|
|
41
|
+
element: this.getElement(),
|
|
42
|
+
onResize: height => this.$emit('resize', height)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
</script>
|