viur-ui 0.0.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/README.md +79 -0
- package/index.d.ts +351 -0
- package/index.js +46 -0
- package/package.json +84 -0
- package/src/components/Browser/Browser.vue +496 -0
- package/src/components/Browser/TreeNav.vue +408 -0
- package/src/components/Browser/ViurBrowser.d.vue.ts +64 -0
- package/src/components/Browser/ViurBrowser.vue +271 -0
- package/src/components/Browser/dragSession.ts +134 -0
- package/src/components/Browser/index.ts +14 -0
- package/src/components/Browser/types.ts +30 -0
- package/src/components/DataTable/ColumnFilterPanel.vue +225 -0
- package/src/components/DataTable/DataTable.vue +3155 -0
- package/src/components/DataTable/ViurDataTable.d.vue.ts +72 -0
- package/src/components/DataTable/ViurDataTable.vue +331 -0
- package/src/components/DataTable/columns.ts +400 -0
- package/src/components/DataTable/index.ts +60 -0
- package/src/components/DataTable/rows.ts +446 -0
- package/src/components/DataTable/types.ts +267 -0
- package/src/components/DataTable/useColumnLayout.ts +294 -0
- package/src/components/DataTable/useGridNavigation.ts +193 -0
- package/src/components/DataTable/useVirtualRows.ts +126 -0
- package/src/components/DataTable/viurColumns.ts +330 -0
- package/src/forms/ViForm.d.vue.ts +106 -0
- package/src/forms/ViForm.vue +592 -0
- package/src/forms/ViFormCategory.vue +57 -0
- package/src/forms/bones/Bone.vue +1023 -0
- package/src/forms/bones/BoneActions.vue +127 -0
- package/src/forms/bones/BoneLabel.vue +122 -0
- package/src/forms/bones/BoneMultipleList.vue +91 -0
- package/src/forms/bones/BoneMultipleWrapper.vue +105 -0
- package/src/forms/bones/BoneNestedWrapper.vue +155 -0
- package/src/forms/bones/BoneSingleEntry.vue +51 -0
- package/src/forms/bones/FilterBone.vue +694 -0
- package/src/forms/bones/actionbar/defaultBar.vue +98 -0
- package/src/forms/bones/actionbar/fileBar.vue +165 -0
- package/src/forms/bones/actionbar/relationalBar.vue +125 -0
- package/src/forms/bones/actions/ActionDialog.vue +70 -0
- package/src/forms/bones/actions/Debug.vue +106 -0
- package/src/forms/bones/actions/Delete.vue +13 -0
- package/src/forms/bones/actions/DescribeImage.vue +201 -0
- package/src/forms/bones/actions/Download.vue +27 -0
- package/src/forms/bones/actions/Placeholder.vue +14 -0
- package/src/forms/bones/actions/Translation.vue +238 -0
- package/src/forms/bones/actions/index.js +280 -0
- package/src/forms/bones/bone.d.ts +45 -0
- package/src/forms/bones/country_information.json +779 -0
- package/src/forms/bones/index.js +225 -0
- package/src/forms/bones/uploadAdapter.js +46 -0
- package/src/forms/bones/utils.js +284 -0
- package/src/forms/bones/view/base_item.vue +35 -0
- package/src/forms/bones/view/boneLogic.js +202 -0
- package/src/forms/bones/view/index.js +5 -0
- package/src/forms/bones/widgets/booleanBone.vue +83 -0
- package/src/forms/bones/widgets/booleanBoneChoose.vue +57 -0
- package/src/forms/bones/widgets/booleanBoneSelect.vue +58 -0
- package/src/forms/bones/widgets/codeBone.vue +214 -0
- package/src/forms/bones/widgets/colorBone.vue +75 -0
- package/src/forms/bones/widgets/dateBone.vue +114 -0
- package/src/forms/bones/widgets/emailBone.vue +100 -0
- package/src/forms/bones/widgets/fileBone.vue +273 -0
- package/src/forms/bones/widgets/jsonBone.vue +63 -0
- package/src/forms/bones/widgets/keyBone.vue +71 -0
- package/src/forms/bones/widgets/numericBone.vue +125 -0
- package/src/forms/bones/widgets/passwordBone.vue +215 -0
- package/src/forms/bones/widgets/phoneBone.vue +173 -0
- package/src/forms/bones/widgets/rawBone.vue +94 -0
- package/src/forms/bones/widgets/recordBone.vue +64 -0
- package/src/forms/bones/widgets/relationalBone.vue +164 -0
- package/src/forms/bones/widgets/relationalBoneSelect.vue +120 -0
- package/src/forms/bones/widgets/selectBone.vue +122 -0
- package/src/forms/bones/widgets/selectBoneChoose.vue +104 -0
- package/src/forms/bones/widgets/spatialBone.vue +111 -0
- package/src/forms/bones/widgets/stringBone.vue +139 -0
- package/src/forms/bones/widgets/textBone.vue +641 -0
- package/src/forms/install.d.ts +4 -0
- package/src/forms/install.js +43 -0
- package/src/forms/layouts/LayloutList2Columns.vue +57 -0
- package/src/forms/layouts/LayoutCategory.vue +38 -0
- package/src/forms/layouts/LayoutList.vue +31 -0
- package/src/forms/utils.js +601 -0
- package/src/public/assets/icons/fontawesome-manifest.json +8 -0
- package/src/public/assets/icons/regular/file.svg +1 -0
- package/src/public/assets/icons/solid/arrows-left-right.svg +1 -0
- package/src/public/assets/icons/solid/bug.svg +1 -0
- package/src/public/assets/icons/solid/check.svg +1 -0
- package/src/public/assets/icons/solid/circle-info.svg +1 -0
- package/src/public/assets/icons/solid/compress.svg +1 -0
- package/src/public/assets/icons/solid/download.svg +1 -0
- package/src/public/assets/icons/solid/expand.svg +1 -0
- package/src/public/assets/icons/solid/grip-vertical.svg +1 -0
- package/src/public/assets/icons/solid/plus.svg +1 -0
- package/src/public/assets/icons/solid/question.svg +1 -0
- package/src/public/assets/icons/solid/triangle-exclamation.svg +1 -0
- package/src/public/assets/icons/solid/upload.svg +1 -0
- package/src/public/assets/icons/solid/xmark.svg +1 -0
- package/src/request/cache.js +183 -0
- package/src/request/configStore.js +516 -0
- package/src/request/envelope.js +211 -0
- package/src/request/index.js +35 -0
- package/src/request/messageStore.js +201 -0
- package/src/request/request.js +752 -0
- package/src/request/skel.js +90 -0
- package/src/theme/colorStore.js +168 -0
- package/src/translations/de.js +178 -0
- package/src/translations/en.js +177 -0
- package/src/user/LoginScreen.d.vue.ts +54 -0
- package/src/user/LoginScreen.vue +627 -0
- package/src/user/google.js +75 -0
- package/src/user/index.js +3 -0
- package/src/user/store.d.ts +59 -0
- package/src/user/store.js +183 -0
- package/src/webawesomeCompat.css +72 -0
- package/src/webawesomeConfig.js +61 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<template
|
|
3
|
+
v-for="(action, i) in state.actions"
|
|
4
|
+
:key="action.arg + '_' + name + '_' + lang + '_' + i"
|
|
5
|
+
>
|
|
6
|
+
<!-- title darf ein i18n-Key sein (z.B. "bone.del") — Klartext bleibt
|
|
7
|
+
Klartext ($te-Prüfung, keine missing-Key-Warnungen). -->
|
|
8
|
+
<wa-button
|
|
9
|
+
:disabled="isActionDisabled(action, ctx)"
|
|
10
|
+
size="medium"
|
|
11
|
+
appearance="outlined"
|
|
12
|
+
:variant="action.variant ?? 'neutral'"
|
|
13
|
+
:title="action.title && $te(action.title) ? $t(action.title) : action.title"
|
|
14
|
+
@click="onClick(action)"
|
|
15
|
+
>
|
|
16
|
+
<wa-icon :name="action.icon"></wa-icon>
|
|
17
|
+
</wa-button>
|
|
18
|
+
|
|
19
|
+
<action-dialog
|
|
20
|
+
v-if="action.type === 'assistant'"
|
|
21
|
+
:open="action._opened"
|
|
22
|
+
:name="bone?.descr"
|
|
23
|
+
:module="bone?.module"
|
|
24
|
+
:action="action"
|
|
25
|
+
:params="{ name, value, index, lang, bone, boneState }"
|
|
26
|
+
@close="onClose"
|
|
27
|
+
@next="onNext"
|
|
28
|
+
></action-dialog>
|
|
29
|
+
</template>
|
|
30
|
+
</template>
|
|
31
|
+
|
|
32
|
+
<script setup>
|
|
33
|
+
import { reactive, computed, onMounted, inject } from "vue"
|
|
34
|
+
import { resolveActions, isActionDisabled, getActionHandler, formConfiguredActions } from "./actions"
|
|
35
|
+
import ActionDialog from "./actions/ActionDialog.vue"
|
|
36
|
+
|
|
37
|
+
const emit = defineEmits(["change"])
|
|
38
|
+
|
|
39
|
+
const props = defineProps({
|
|
40
|
+
name: String,
|
|
41
|
+
value: [Object, String, Number, Boolean, Array],
|
|
42
|
+
index: Number,
|
|
43
|
+
lang: String,
|
|
44
|
+
bone: Object,
|
|
45
|
+
/**
|
|
46
|
+
* Welche Actions diese Leiste zeigt:
|
|
47
|
+
* - "entry": alle bei `boneactions`, sonst nur die Pflicht-Actions (Standard)
|
|
48
|
+
* - "value": nur die Pflicht-Actions — am Wert EINER Sprache eines
|
|
49
|
+
* mehrsprachigen Bones (Löschen/Download betreffen nur diese Sprache)
|
|
50
|
+
* - "bone": nur die übrigen — die Leiste neben den Sprach-Tabs (Übersetzen …)
|
|
51
|
+
*/
|
|
52
|
+
scope: {
|
|
53
|
+
type: String,
|
|
54
|
+
default: "entry",
|
|
55
|
+
validator: (value) => ["entry", "value", "bone"].includes(value),
|
|
56
|
+
},
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
const boneState = inject("boneState")
|
|
60
|
+
// Vom HOST bereitgestellte Auswahl für relationale Bones (z.B. ein Admin, der
|
|
61
|
+
// einen Listen-Dialog öffnet): `(request) => Promise<Row[]|null>`. Ohne
|
|
62
|
+
// Provider existiert die zugehörige Action schlicht nicht (`when`-Prädikat).
|
|
63
|
+
const relationSelector = inject("viurRelationSelector", null)
|
|
64
|
+
// Für Mehrfach-Übernahme in multiple-Bones (hängt weitere Einträge an) und
|
|
65
|
+
// die Pflicht-Action "Zeile entfernen".
|
|
66
|
+
const addMultipleEntry = inject("addMultipleEntry", null)
|
|
67
|
+
const removeMultipleEntry = inject("removeMultipleEntry", null)
|
|
68
|
+
// Formular-weite Action-Konfiguration (ViForm `actions`-Prop).
|
|
69
|
+
const boneActionsConfig = inject("boneActionsConfig", null)
|
|
70
|
+
|
|
71
|
+
const state = reactive({
|
|
72
|
+
actions: [],
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
/** Steckt diese Action-Leiste in einer ZEILE eines multiple-Bones? */
|
|
76
|
+
const multipleRow = props.index !== null && props.index !== undefined
|
|
77
|
+
|
|
78
|
+
const ctx = computed(() => ({
|
|
79
|
+
name: props.name,
|
|
80
|
+
value: props.value,
|
|
81
|
+
index: props.index,
|
|
82
|
+
lang: props.lang,
|
|
83
|
+
bone: props.bone,
|
|
84
|
+
boneState,
|
|
85
|
+
relationSelector,
|
|
86
|
+
multipleRow,
|
|
87
|
+
update: (val) => emit("change", props.name, val, props.lang, props.index),
|
|
88
|
+
/** Weiteren Eintrag ans Multiple-Array hängen (Mehrfach-Auswahl). */
|
|
89
|
+
appendEntry: (val) => addMultipleEntry?.(props.lang ?? null, val),
|
|
90
|
+
/** DIESE Zeile aus dem Multiple-Array entfernen (Pflicht-Action). */
|
|
91
|
+
removeEntry: () => removeMultipleEntry?.(props.index, props.lang ?? null),
|
|
92
|
+
}))
|
|
93
|
+
|
|
94
|
+
onMounted(() => {
|
|
95
|
+
// Formular-Konfiguration VOR den Bone-eigenen params.actions (Bone-Lokales
|
|
96
|
+
// ist spezifischer); Minus-Einträge gewinnen quellenunabhängig immer.
|
|
97
|
+
const configured = [...formConfiguredActions(boneActionsConfig, props.name), ...(props.bone?.params?.actions ?? [])]
|
|
98
|
+
const all = resolveActions(props.bone, configured, boneState, { relationSelector, multipleRow })
|
|
99
|
+
// Ohne `boneactions` bleiben nur die PFLICHT-Actions (Gerüst, z.B. das
|
|
100
|
+
// Zeilen-X) — die Leiste als Ganzes ist Opt-in, das Gerüst nicht.
|
|
101
|
+
if (props.scope === "bone") {
|
|
102
|
+
state.actions = all.filter((action) => !action.required)
|
|
103
|
+
} else if (props.scope === "value" || !boneState?.boneactions) {
|
|
104
|
+
state.actions = all.filter((action) => action.required)
|
|
105
|
+
} else {
|
|
106
|
+
state.actions = all
|
|
107
|
+
}
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
function onClick(action) {
|
|
111
|
+
if (action.type === "assistant") {
|
|
112
|
+
action._opened = true
|
|
113
|
+
} else if (action.type === "callback") {
|
|
114
|
+
const handler = getActionHandler(action.arg)
|
|
115
|
+
handler?.(ctx.value)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function onClose(val, lang, action) {
|
|
120
|
+
action._opened = false
|
|
121
|
+
if (val) emit("change", props.name, val, lang, props.index)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function onNext(val, lang, action) {
|
|
125
|
+
if (val) emit("change", props.name, val, lang, props.index)
|
|
126
|
+
}
|
|
127
|
+
</script>
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<label class="bone-label">
|
|
3
|
+
<slot v-if="!debug"></slot>
|
|
4
|
+
<wa-tooltip
|
|
5
|
+
v-else
|
|
6
|
+
:for="tooltipTargetId"
|
|
7
|
+
:content="name"
|
|
8
|
+
></wa-tooltip>
|
|
9
|
+
<span
|
|
10
|
+
v-if="debug"
|
|
11
|
+
:id="tooltipTargetId"
|
|
12
|
+
>
|
|
13
|
+
<slot></slot>
|
|
14
|
+
</span>
|
|
15
|
+
<template v-if="debug">
|
|
16
|
+
<div
|
|
17
|
+
class="debug"
|
|
18
|
+
@click="state.debug = !state.debug"
|
|
19
|
+
>
|
|
20
|
+
<wa-icon name="bug"></wa-icon>
|
|
21
|
+
</div>
|
|
22
|
+
</template>
|
|
23
|
+
</label>
|
|
24
|
+
|
|
25
|
+
<wa-dialog
|
|
26
|
+
v-if="state.debug"
|
|
27
|
+
open
|
|
28
|
+
:label="name"
|
|
29
|
+
@wa-after-hide="state.debug = false"
|
|
30
|
+
>
|
|
31
|
+
<pre>
|
|
32
|
+
{{ boneState }}
|
|
33
|
+
</pre
|
|
34
|
+
>
|
|
35
|
+
</wa-dialog>
|
|
36
|
+
</template>
|
|
37
|
+
|
|
38
|
+
<script setup>
|
|
39
|
+
import { reactive, inject, computed, unref } from "vue"
|
|
40
|
+
import { buildBoneDomId } from "./utils"
|
|
41
|
+
const props = defineProps({
|
|
42
|
+
name: String,
|
|
43
|
+
value: Object,
|
|
44
|
+
index: Number,
|
|
45
|
+
lang: String,
|
|
46
|
+
readonly: Boolean,
|
|
47
|
+
params: Object,
|
|
48
|
+
debug: {
|
|
49
|
+
type: Boolean,
|
|
50
|
+
default: false,
|
|
51
|
+
},
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
const emit = defineEmits(["change", "handleClick"])
|
|
55
|
+
|
|
56
|
+
const boneState = inject("boneState")
|
|
57
|
+
const bonePath = inject("bonePath", [])
|
|
58
|
+
const tooltipTargetId = computed(() => buildBoneDomId(unref(bonePath) ?? [], "debug-label"))
|
|
59
|
+
const state = reactive({
|
|
60
|
+
debug: false,
|
|
61
|
+
})
|
|
62
|
+
</script>
|
|
63
|
+
<style scoped>
|
|
64
|
+
@layer foundation.form {
|
|
65
|
+
.bone-label {
|
|
66
|
+
display: flex;
|
|
67
|
+
width: 100%;
|
|
68
|
+
box-sizing: border-box;
|
|
69
|
+
padding: var(--wa-space-xs) var(--wa-space-xs);
|
|
70
|
+
background-color: var(--wa-color-fill-quiet);
|
|
71
|
+
color: var(--wa-color-text-normal);
|
|
72
|
+
border-radius: var(--wa-border-radius-m);
|
|
73
|
+
word-break: break-word;
|
|
74
|
+
align-self: flex-start;
|
|
75
|
+
min-height: var(--wa-form-control-height);
|
|
76
|
+
align-items: center;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
</style>
|
|
80
|
+
|
|
81
|
+
<!--
|
|
82
|
+
<style scoped>
|
|
83
|
+
@layer foundation.form {
|
|
84
|
+
.bone-name {
|
|
85
|
+
display: flex;
|
|
86
|
+
flex-direction: row;
|
|
87
|
+
align-items: center;
|
|
88
|
+
align-self: flex-start;
|
|
89
|
+
font-size: var(--wa-input-font-size-medium);
|
|
90
|
+
min-height: var(--wa-input-height-medium);
|
|
91
|
+
padding: 0.4em 0.7em;
|
|
92
|
+
color: var(--wa-color-neutral-10);
|
|
93
|
+
background-color: var(--wa-color-neutral-90);
|
|
94
|
+
border: none;
|
|
95
|
+
border-top-left-radius: var(--wa-input-border-radius-medium);
|
|
96
|
+
border-bottom-left-radius: var(--wa-input-border-radius-medium);
|
|
97
|
+
word-break: break-word;
|
|
98
|
+
|
|
99
|
+
@media (max-width: 900px) {
|
|
100
|
+
border-top-right-radius: var(--wa-input-border-radius-medium);
|
|
101
|
+
border-bottom-left-radius: 0;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.debug {
|
|
106
|
+
display: flex;
|
|
107
|
+
align-items: center;
|
|
108
|
+
justify-content: center;
|
|
109
|
+
margin-left: auto;
|
|
110
|
+
padding-left: 0.4em;
|
|
111
|
+
|
|
112
|
+
& wa-icon {
|
|
113
|
+
background-color: var(--wa-color-danger-50);
|
|
114
|
+
color: #fff;
|
|
115
|
+
padding: 0.4em;
|
|
116
|
+
border-radius: 50%;
|
|
117
|
+
font-size: 0.55em;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
</style>
|
|
122
|
+
-->
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<template v-if="entries?.length">
|
|
3
|
+
<vue-draggable
|
|
4
|
+
v-model="localEntries"
|
|
5
|
+
:animation="150"
|
|
6
|
+
handle=".bone-drag-button"
|
|
7
|
+
class="wa-stack wa-gap-xs bone-multiple-list"
|
|
8
|
+
>
|
|
9
|
+
<div
|
|
10
|
+
v-for="(val, index) in entries"
|
|
11
|
+
:key="val?._key ? val._key : index + '_' + entries.length"
|
|
12
|
+
class="bone-multiple-wrapper"
|
|
13
|
+
>
|
|
14
|
+
<bone-multiple-wrapper
|
|
15
|
+
:readonly="!readonly"
|
|
16
|
+
:index="index"
|
|
17
|
+
:lang="lang"
|
|
18
|
+
:name="name"
|
|
19
|
+
>
|
|
20
|
+
<component
|
|
21
|
+
:is="is"
|
|
22
|
+
:value="resolveValue(val, index)"
|
|
23
|
+
:index="index"
|
|
24
|
+
:lang="lang"
|
|
25
|
+
:name="name"
|
|
26
|
+
:bone="bonestructure"
|
|
27
|
+
@change="updateValue"
|
|
28
|
+
/>
|
|
29
|
+
</bone-multiple-wrapper>
|
|
30
|
+
</div>
|
|
31
|
+
</vue-draggable>
|
|
32
|
+
</template>
|
|
33
|
+
<div
|
|
34
|
+
v-else
|
|
35
|
+
class="bone-multiple-placeholder"
|
|
36
|
+
:class="{ 'is-readonly': readonly }"
|
|
37
|
+
>
|
|
38
|
+
<wa-input
|
|
39
|
+
readonly
|
|
40
|
+
size="medium"
|
|
41
|
+
:placeholder="$t('bone.no_entries')"
|
|
42
|
+
/>
|
|
43
|
+
</div>
|
|
44
|
+
<component
|
|
45
|
+
:is="actionbar"
|
|
46
|
+
v-if="!readonly && actionbar"
|
|
47
|
+
:value="entries"
|
|
48
|
+
:name="name"
|
|
49
|
+
:lang="lang"
|
|
50
|
+
@change="updateValue"
|
|
51
|
+
/>
|
|
52
|
+
</template>
|
|
53
|
+
|
|
54
|
+
<script setup>
|
|
55
|
+
import { computed, inject } from "vue"
|
|
56
|
+
import { VueDraggable } from "vue-draggable-plus"
|
|
57
|
+
import BoneMultipleWrapper from "./BoneMultipleWrapper.vue"
|
|
58
|
+
|
|
59
|
+
const props = defineProps({
|
|
60
|
+
is: { type: Object, required: true },
|
|
61
|
+
name: { type: String, required: true },
|
|
62
|
+
lang: { type: String, default: null },
|
|
63
|
+
entries: { type: Array, default: null },
|
|
64
|
+
bonestructure: { type: Object, required: true },
|
|
65
|
+
readonly: { type: Boolean, default: false },
|
|
66
|
+
actionbar: { type: Object, default: null },
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
const updateValue = inject("updateValue")
|
|
70
|
+
|
|
71
|
+
const localEntries = computed({
|
|
72
|
+
get: () => props.entries ?? [],
|
|
73
|
+
set: (newVal) => updateValue(props.name, newVal, props.lang),
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
function resolveValue(val, index) {
|
|
77
|
+
const defaultvalue = props.bonestructure?.defaultvalue
|
|
78
|
+
if (!val && defaultvalue) {
|
|
79
|
+
return props.lang ? defaultvalue[props.lang]?.[index] : defaultvalue?.[index]
|
|
80
|
+
}
|
|
81
|
+
return val
|
|
82
|
+
}
|
|
83
|
+
</script>
|
|
84
|
+
<style scoped>
|
|
85
|
+
.bone-multiple-list {
|
|
86
|
+
background-color: var(--wa-color-surface-lowered);
|
|
87
|
+
padding: var(--wa-space-xs);
|
|
88
|
+
border-radius: var(--wa-border-radius-m);
|
|
89
|
+
border: 1px solid var(--wa-color-surface-border);
|
|
90
|
+
}
|
|
91
|
+
</style>
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="wa-flank wa-align-items-start wa-gap-xs bone-multiple-entry">
|
|
3
|
+
<wa-button
|
|
4
|
+
appearance="filled"
|
|
5
|
+
:disabled="boneState.readonly"
|
|
6
|
+
class="bone-drag-button"
|
|
7
|
+
>
|
|
8
|
+
<wa-icon name="grip-vertical"></wa-icon>
|
|
9
|
+
</wa-button>
|
|
10
|
+
<div class="wa-flank:end wa-gap-xs wa-align-items-start">
|
|
11
|
+
<div class="value">
|
|
12
|
+
<slot></slot>
|
|
13
|
+
</div>
|
|
14
|
+
<div class="wa-cluster wa-gap-xs">
|
|
15
|
+
<!-- IMMER gerendert: Das Zeilen-X ist die Pflicht-Action "removeEntry"
|
|
16
|
+
(actions/index.js) — BoneActions filtert ohne `boneactions` selbst
|
|
17
|
+
auf die Pflicht-Actions herunter. -->
|
|
18
|
+
<bone-actions
|
|
19
|
+
:value="state.value"
|
|
20
|
+
:name="name"
|
|
21
|
+
:lang="lang"
|
|
22
|
+
:index="index"
|
|
23
|
+
:bone="boneState.bonestructure"
|
|
24
|
+
@change="updateValue"
|
|
25
|
+
></bone-actions>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
</template>
|
|
30
|
+
|
|
31
|
+
<script setup>
|
|
32
|
+
import { reactive, inject, computed } from "vue"
|
|
33
|
+
import BoneActions from "./BoneActions.vue"
|
|
34
|
+
|
|
35
|
+
const props = defineProps({
|
|
36
|
+
index: Number,
|
|
37
|
+
name: String,
|
|
38
|
+
lang: {
|
|
39
|
+
default: null,
|
|
40
|
+
},
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
const state = reactive({
|
|
44
|
+
value: computed(() => {
|
|
45
|
+
if (props.lang) {
|
|
46
|
+
return boneState.bonevalue[props.lang][props.index]
|
|
47
|
+
}
|
|
48
|
+
return boneState.bonevalue[props.index]
|
|
49
|
+
}),
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
const boneState = inject("boneState")
|
|
54
|
+
const updateValue = inject("updateValue")
|
|
55
|
+
</script>
|
|
56
|
+
<!--
|
|
57
|
+
<style scoped>
|
|
58
|
+
.value-line {
|
|
59
|
+
display: flex;
|
|
60
|
+
gap: var(--wa-space-xs);
|
|
61
|
+
align-items: flex-start;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.value {
|
|
65
|
+
flex: 1 1 100%;
|
|
66
|
+
width: 1px;
|
|
67
|
+
|
|
68
|
+
& :deep(wa-input) {
|
|
69
|
+
&::part(base) {
|
|
70
|
+
border-bottom-left-radius: var(--wa-border-radius-m);
|
|
71
|
+
border-top-left-radius: var(--wa-border-radius-m);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
& :deep(.bone-wrapper) {
|
|
76
|
+
& wa-input::part(base) {
|
|
77
|
+
border-bottom-left-radius: 0;
|
|
78
|
+
border-top-left-radius: 0;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
&:deep(wa-alert) {
|
|
83
|
+
&::part(base) {
|
|
84
|
+
margin-top: 0;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.delete-btn {
|
|
90
|
+
transition: all ease 0.3s;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.drag-button {
|
|
94
|
+
&::part(base) {
|
|
95
|
+
aspect-ratio: 1;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
.row-wrapper {
|
|
99
|
+
width: 100%;
|
|
100
|
+
display: flex;
|
|
101
|
+
flex-direction: row;
|
|
102
|
+
gap: var(--wa-space-xs);
|
|
103
|
+
}
|
|
104
|
+
</style>
|
|
105
|
+
-->
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<wa-alert
|
|
3
|
+
v-if="!state.globalRegistration"
|
|
4
|
+
open
|
|
5
|
+
variant="danger"
|
|
6
|
+
>
|
|
7
|
+
In Order to use this Bone register the bone component globally in your main file
|
|
8
|
+
</wa-alert>
|
|
9
|
+
<div
|
|
10
|
+
v-else
|
|
11
|
+
class="form"
|
|
12
|
+
>
|
|
13
|
+
<wa-spinner
|
|
14
|
+
v-if="state.updating"
|
|
15
|
+
style="position: absolute; top: 20px; left: -10px"
|
|
16
|
+
></wa-spinner>
|
|
17
|
+
|
|
18
|
+
<vi-form
|
|
19
|
+
ref="skelRef"
|
|
20
|
+
:internal="mainformState"
|
|
21
|
+
:skel="value"
|
|
22
|
+
:structure="bone['using']"
|
|
23
|
+
:renderer="state.renderer"
|
|
24
|
+
:use-categories="bone?.params['categoryDefaultname'] !== null"
|
|
25
|
+
:category-defaultname="nestedCategory()"
|
|
26
|
+
:collapsed-categories="
|
|
27
|
+
state.isLastEntry ? [] : bone?.params?.['collapsedCategories'] ? bone?.params?.['collapsedCategories'] : []
|
|
28
|
+
"
|
|
29
|
+
:readonly="mainformState.readonly"
|
|
30
|
+
:boneactions="mainformState.boneactions"
|
|
31
|
+
:actions="parentActionsConfig"
|
|
32
|
+
@change="changeEvent"
|
|
33
|
+
></vi-form>
|
|
34
|
+
</div>
|
|
35
|
+
</template>
|
|
36
|
+
|
|
37
|
+
<script setup>
|
|
38
|
+
import {
|
|
39
|
+
reactive,
|
|
40
|
+
defineComponent,
|
|
41
|
+
onMounted,
|
|
42
|
+
inject,
|
|
43
|
+
computed,
|
|
44
|
+
getCurrentInstance,
|
|
45
|
+
watch,
|
|
46
|
+
ref,
|
|
47
|
+
provide,
|
|
48
|
+
unref,
|
|
49
|
+
} from "vue"
|
|
50
|
+
import { getBoneWidget } from "./index"
|
|
51
|
+
import ViForm from "../ViForm.vue"
|
|
52
|
+
import { useTimeoutFn } from "@vueuse/core"
|
|
53
|
+
|
|
54
|
+
const emit = defineEmits(["change"])
|
|
55
|
+
const props = defineProps({
|
|
56
|
+
name: String,
|
|
57
|
+
value: null,
|
|
58
|
+
index: Number,
|
|
59
|
+
lang: String,
|
|
60
|
+
readonly: Boolean,
|
|
61
|
+
params: Object,
|
|
62
|
+
bone: Object,
|
|
63
|
+
})
|
|
64
|
+
const skelRef = ref(null)
|
|
65
|
+
const boneState = inject("boneState")
|
|
66
|
+
const mainformState = inject("mainformState")
|
|
67
|
+
// Action-Konfiguration des umgebenden Formulars (ViForm `actions`) — das
|
|
68
|
+
// Unterformular stellt sonst seine eigene (leere) bereit.
|
|
69
|
+
const parentActionsConfig = inject("boneActionsConfig", null)
|
|
70
|
+
const parentBonePath = inject("bonePath", [])
|
|
71
|
+
const bonePath = computed(() => {
|
|
72
|
+
const path = [...(unref(parentBonePath) ?? []), props.name]
|
|
73
|
+
|
|
74
|
+
if (props.lang) {
|
|
75
|
+
path.push(`lang-${props.lang}`)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (props.index !== null && props.index !== undefined) {
|
|
79
|
+
path.push(`idx-${props.index}`)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return path
|
|
83
|
+
})
|
|
84
|
+
provide("bonePath", bonePath)
|
|
85
|
+
const state = reactive({
|
|
86
|
+
renderer: import.meta.env.VITE_DEFAULT_RENDERER || "json",
|
|
87
|
+
globalRegistration: false,
|
|
88
|
+
isLastEntry: computed(() => {
|
|
89
|
+
if (!props.bone["multiple"]) return false
|
|
90
|
+
|
|
91
|
+
let val = mainformState.skel[props.name]
|
|
92
|
+
if (props.lang) {
|
|
93
|
+
val = mainformState.skel[props.name][props.lang]
|
|
94
|
+
}
|
|
95
|
+
if (!val) {
|
|
96
|
+
return false
|
|
97
|
+
}
|
|
98
|
+
return val.length - 1 === props.index
|
|
99
|
+
}),
|
|
100
|
+
updating: false,
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
function changeEvent(val) {
|
|
104
|
+
state.updating = true
|
|
105
|
+
val["value"] = skelRef.value.state.skel // send whole form
|
|
106
|
+
val["name"] = props.name
|
|
107
|
+
val["index"] = props.index
|
|
108
|
+
val["lang"] = props.lang
|
|
109
|
+
emit("change", val)
|
|
110
|
+
useTimeoutFn(() => {
|
|
111
|
+
state.updating = false
|
|
112
|
+
}, 1000)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
watch(
|
|
116
|
+
() => props.value,
|
|
117
|
+
(newVal, oldVal) => {
|
|
118
|
+
state.updating = false
|
|
119
|
+
}
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
onMounted(() => {
|
|
123
|
+
let app = getCurrentInstance().appContext
|
|
124
|
+
if (app.components.Bone) {
|
|
125
|
+
state.globalRegistration = true
|
|
126
|
+
} else {
|
|
127
|
+
state.globalRegistration = false
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
let val = {}
|
|
131
|
+
if (props.value) val = props.value
|
|
132
|
+
|
|
133
|
+
for (const [bonename, boneStructure] of Object.entries(props.bone["using"])) {
|
|
134
|
+
if (!Object.keys(val).includes(bonename) && boneStructure["defaultvalue"]) {
|
|
135
|
+
val[bonename] = boneStructure["defaultvalue"]
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
emit("change", props.name, val, props.lang, props.index) //init
|
|
140
|
+
})
|
|
141
|
+
function nestedCategory() {
|
|
142
|
+
if (props.bone?.params?.["categoryDefaultname"]) {
|
|
143
|
+
return props.bone.params["categoryDefaultname"]
|
|
144
|
+
} else if (props.bone?.format) {
|
|
145
|
+
return props.bone.format
|
|
146
|
+
}
|
|
147
|
+
return undefined
|
|
148
|
+
}
|
|
149
|
+
</script>
|
|
150
|
+
<style scoped>
|
|
151
|
+
.form {
|
|
152
|
+
width: 100%;
|
|
153
|
+
position: relative;
|
|
154
|
+
}
|
|
155
|
+
</style>
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="wa-flank:end bone-row wa-gap-xs wa-align-items-start">
|
|
3
|
+
<div class="bone-block">
|
|
4
|
+
<component
|
|
5
|
+
:is="is"
|
|
6
|
+
:value="bonevalue"
|
|
7
|
+
:name="name"
|
|
8
|
+
:index="null"
|
|
9
|
+
:lang="lang"
|
|
10
|
+
:bone="bonestructure"
|
|
11
|
+
:autofocus="autofocus"
|
|
12
|
+
@change="updateValue"
|
|
13
|
+
@keypress.enter="updateValue"
|
|
14
|
+
></component>
|
|
15
|
+
</div>
|
|
16
|
+
<!-- Pflicht-Actions (Löschen, Download …) auch ohne `boneactions`; am
|
|
17
|
+
Wert DIESES Eintrags, bei Mehrsprachigkeit also seiner Sprache -->
|
|
18
|
+
<div
|
|
19
|
+
v-if="(boneactions && boneState?.hasActions) || boneState?.hasRequiredActions"
|
|
20
|
+
class="wa-cluster wa-gap-xs"
|
|
21
|
+
>
|
|
22
|
+
<bone-actions
|
|
23
|
+
:value="bonevalue"
|
|
24
|
+
:name="name"
|
|
25
|
+
:index="null"
|
|
26
|
+
:lang="lang"
|
|
27
|
+
:bone="bonestructure"
|
|
28
|
+
:scope="boneactions ? 'entry' : 'value'"
|
|
29
|
+
@change="updateValue"
|
|
30
|
+
></bone-actions>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
</template>
|
|
34
|
+
|
|
35
|
+
<script setup>
|
|
36
|
+
import { inject } from "vue"
|
|
37
|
+
import BoneActions from "./BoneActions.vue"
|
|
38
|
+
|
|
39
|
+
const props = defineProps({
|
|
40
|
+
is: { type: Object, required: true },
|
|
41
|
+
name: { type: String, required: true },
|
|
42
|
+
lang: { type: String, default: null },
|
|
43
|
+
bonevalue: { default: null },
|
|
44
|
+
bonestructure: { type: Object, required: true },
|
|
45
|
+
boneactions: { type: Boolean, default: true },
|
|
46
|
+
autofocus: { type: Boolean, default: false },
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
const updateValue = inject("updateValue")
|
|
50
|
+
const boneState = inject("boneState")
|
|
51
|
+
</script>
|