comand-component-library 3.3.84 → 3.3.86
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/comand-component-library.js +5623 -3929
- package/dist/comand-component-library.umd.cjs +4 -4
- package/dist/style.css +1 -1
- package/package.json +2 -2
- package/src/App.vue +215 -112
- package/src/assets/data/component-structure.json +228 -0
- package/src/assets/data/form-elements.json +156 -0
- package/src/assets/data/opening-hours.json +79 -37
- package/src/components/CmdAddressData.vue +187 -201
- package/src/components/CmdAddressDataItem.vue +306 -0
- package/src/components/CmdBox.vue +1 -0
- package/src/components/CmdBoxWrapper.vue +53 -5
- package/src/components/CmdFancyBox.vue +31 -4
- package/src/components/CmdForm.vue +98 -4
- package/src/components/CmdFormElement.vue +5 -1
- package/src/components/CmdHeadline.vue +179 -52
- package/src/components/CmdImage.vue +205 -76
- package/src/components/CmdImageGallery.vue +88 -85
- package/src/components/CmdListOfLinks.vue +63 -43
- package/src/components/CmdListOfLinksItem.vue +97 -0
- package/src/components/CmdLoginForm.vue +3 -6
- package/src/components/CmdMultistepFormProgressBar.vue +37 -8
- package/src/components/CmdOpeningHours.vue +280 -63
- package/src/components/CmdOpeningHoursItem.vue +264 -0
- package/src/components/{CmdPager.vue → CmdPagination.vue} +2 -2
- package/src/components/CmdSlideshow.vue +137 -10
- package/src/components/CmdSocialNetworks.vue +115 -28
- package/src/components/CmdSocialNetworksItem.vue +184 -0
- package/src/components/CmdTable.vue +0 -1
- package/src/components/CmdTextImageBlock.vue +158 -0
- package/src/components/CmdThumbnailScroller.vue +132 -12
- package/src/components/CmdToggleDarkMode.vue +58 -1
- package/src/components/EditComponentWrapper.vue +553 -0
- package/src/index.js +2 -2
- package/src/mixins/EditMode.vue +28 -9
- package/src/utils/editmode.js +30 -5
- package/src/components/CmdTextBlock.vue +0 -73
- package/src/editmode/editModeContext.js +0 -50
@@ -0,0 +1,306 @@
|
|
1
|
+
<template>
|
2
|
+
<dt :class="['cmd-address-data-item', {'address': addressEntry.type === 'address'}]">
|
3
|
+
<!-- begin CmdIcon -->
|
4
|
+
<CmdIcon
|
5
|
+
v-if="addressEntry.iconClass && showLabelIcons"
|
6
|
+
:iconClass="addressEntry.iconClass"
|
7
|
+
:type="addressEntry.iconType"
|
8
|
+
:tooltip="addressEntry.labelText"
|
9
|
+
/>
|
10
|
+
<!-- end CmdIcon -->
|
11
|
+
<span v-if="showLabelTexts">{{ addressEntry.labelText }}</span>
|
12
|
+
</dt>
|
13
|
+
<!-- end labels -->
|
14
|
+
|
15
|
+
<!-- begin data (except for address) -->
|
16
|
+
<dd v-if="addressEntry.type !== 'address' && (addressEntry.data || addressEntry.href)" :class="vCardClass(addressEntry)">
|
17
|
+
<template v-if="!editing">
|
18
|
+
<a v-if="addressEntry.href"
|
19
|
+
:href="getHref(addressEntry)"
|
20
|
+
:target="addressEntry.type === 'url' ? '_blank' : null"
|
21
|
+
:title="addressEntry.tooltip"
|
22
|
+
:data-type="addressEntry.type"
|
23
|
+
v-telephone="addressEntry.href">
|
24
|
+
{{ addressEntry.data || addressEntry.href }}
|
25
|
+
</a>
|
26
|
+
<span v-else v-html="addressEntry.data"></span>
|
27
|
+
</template>
|
28
|
+
|
29
|
+
<!-- begin edit-mode -->
|
30
|
+
<CmdFormElement
|
31
|
+
v-else
|
32
|
+
element="input"
|
33
|
+
:type="inputType(addressEntry)"
|
34
|
+
class="edit-mode"
|
35
|
+
:show-label="false"
|
36
|
+
:labelText="addressEntry.labelText"
|
37
|
+
:placeholder="addressEntry.labelText"
|
38
|
+
v-model="editableAddressEntry"
|
39
|
+
/>
|
40
|
+
<!-- end edit-mode -->
|
41
|
+
</dd>
|
42
|
+
|
43
|
+
<!-- begin data for address -->
|
44
|
+
<dd v-else-if="addressEntry.type === 'address'">
|
45
|
+
<!-- begin linked address -->
|
46
|
+
<a v-if="linkGoogleMaps && !editing"
|
47
|
+
:href="locateAddress(addressEntry)"
|
48
|
+
target="google-maps"
|
49
|
+
:title="addressEntry.tooltip">
|
50
|
+
<!-- begin street/number -->
|
51
|
+
<template v-if="addressEntry.streetNo">
|
52
|
+
<span class="street-address">{{ addressEntry.streetNo }}</span><br/>
|
53
|
+
</template>
|
54
|
+
<!-- end street/number -->
|
55
|
+
|
56
|
+
<!-- begin zip/city -->
|
57
|
+
<span v-if="addressEntry.zip" class="postal-code">{{ addressEntry.zip }}</span>
|
58
|
+
<template v-if="addressEntry.city">
|
59
|
+
<span class="locality">{{ addressEntry.city }}</span><br/>
|
60
|
+
</template>
|
61
|
+
<!-- end zip/city -->
|
62
|
+
|
63
|
+
<!-- begin miscInfo -->
|
64
|
+
<template v-if="addressEntry.miscInfo">
|
65
|
+
<span>{{ addressEntry.miscInfo }}</span><br v-if="addressEntry.country" />
|
66
|
+
</template>
|
67
|
+
<!-- end miscInfo -->
|
68
|
+
|
69
|
+
<!-- begin country -->
|
70
|
+
<span v-if="addressEntry.country" class="country-name">{{ addressEntry.country }}</span>
|
71
|
+
<!-- end country -->
|
72
|
+
</a>
|
73
|
+
<!-- end linked address -->
|
74
|
+
|
75
|
+
<!-- begin unlinked address -->
|
76
|
+
<template v-else>
|
77
|
+
<template v-if="!editing">
|
78
|
+
<!-- begin street/number -->
|
79
|
+
<template v-if="addressEntry.streetNo">
|
80
|
+
<span class="street-address">{{ addressEntry.streetNo }}</span><br/>
|
81
|
+
</template>
|
82
|
+
<!-- end street/number -->
|
83
|
+
|
84
|
+
<!-- begin zip/city -->
|
85
|
+
<span v-if="addressEntry.zip" class="postal-code">{{ addressEntry.zip }} </span>
|
86
|
+
<template v-if="addressEntry.city">
|
87
|
+
<span class="locality">{{ addressEntry.city }}</span><br/>
|
88
|
+
</template>
|
89
|
+
<!-- end zip/city -->
|
90
|
+
|
91
|
+
<!-- begin miscInfo -->
|
92
|
+
<template v-if="addressEntry.miscInfo">
|
93
|
+
<span>{{ addressEntry.miscInfo }}</span><br/>
|
94
|
+
</template>
|
95
|
+
<!-- end miscInfo -->
|
96
|
+
|
97
|
+
<!-- begin country -->
|
98
|
+
<span v-if="addressEntry.country" class="country-name">{{ addressEntry.country }}</span>
|
99
|
+
<!-- end country -->
|
100
|
+
</template>
|
101
|
+
|
102
|
+
<!-- begin edit-mode for address -->
|
103
|
+
<template v-else>
|
104
|
+
<!-- begin street/number -->
|
105
|
+
<CmdFormElement
|
106
|
+
element="input"
|
107
|
+
type="text"
|
108
|
+
class="edit-mode"
|
109
|
+
:show-label="false"
|
110
|
+
:labelText="addressEntry.labelText"
|
111
|
+
:placeholder="addressEntry.labelText"
|
112
|
+
v-model="editableAddressEntry.streetNo"
|
113
|
+
/>
|
114
|
+
<!-- end street/number -->
|
115
|
+
|
116
|
+
<!-- begin zip/city -->
|
117
|
+
<div class="input-wrapper">
|
118
|
+
<CmdFormElement
|
119
|
+
element="input"
|
120
|
+
type="text"
|
121
|
+
class="edit-mode"
|
122
|
+
:show-label="false"
|
123
|
+
:labelText="addressEntry.labelText"
|
124
|
+
:placeholder="addressEntry.labelText"
|
125
|
+
v-model="editableAddressEntry.zip"
|
126
|
+
/>
|
127
|
+
<CmdFormElement
|
128
|
+
element="input"
|
129
|
+
type="text"
|
130
|
+
class="edit-mode"
|
131
|
+
:show-label="false"
|
132
|
+
:labelText="addressEntry.labelText"
|
133
|
+
:placeholder="addressEntry.labelText"
|
134
|
+
v-model="editableAddressEntry.city"
|
135
|
+
/>
|
136
|
+
</div>
|
137
|
+
<!-- end zip/city -->
|
138
|
+
|
139
|
+
<!-- begin miscInfo -->
|
140
|
+
<CmdFormElement
|
141
|
+
element="input"
|
142
|
+
type="text"
|
143
|
+
class="edit-mode"
|
144
|
+
:show-label="false"
|
145
|
+
:labelText="addressEntry.labelText"
|
146
|
+
:placeholder="addressEntry.labelText"
|
147
|
+
v-model="editableAddressEntry.miscInfo"
|
148
|
+
/>
|
149
|
+
<!-- end miscInfo -->
|
150
|
+
|
151
|
+
<!-- begin country -->
|
152
|
+
<CmdFormElement
|
153
|
+
element="select"
|
154
|
+
class="edit-mode"
|
155
|
+
:show-label="false"
|
156
|
+
:labelText="addressEntry.labelText"
|
157
|
+
:selectOptions="[{text: 'Germany', value: 'de'}, {text: 'United Kingdom', value: 'uk'}]"
|
158
|
+
v-model="editableAddressEntry.country"
|
159
|
+
/>
|
160
|
+
<!-- end country -->
|
161
|
+
</template>
|
162
|
+
<!-- end edit-mode for address -->
|
163
|
+
</template>
|
164
|
+
<!-- end unlinked address -->
|
165
|
+
</dd>
|
166
|
+
<!-- end data for address -->
|
167
|
+
|
168
|
+
</template>
|
169
|
+
<!-- end data (except for address) -->
|
170
|
+
<script>
|
171
|
+
import EditMode from "../mixins/EditMode.vue"
|
172
|
+
import {updateHandlerProvider} from "../utils/editmode.js";
|
173
|
+
|
174
|
+
export default {
|
175
|
+
name: "CmdAddressDataItem",
|
176
|
+
mixins: [EditMode],
|
177
|
+
data() {
|
178
|
+
return {
|
179
|
+
editableAddressEntry: null
|
180
|
+
}
|
181
|
+
},
|
182
|
+
props: {
|
183
|
+
addressEntry: {
|
184
|
+
type: Object,
|
185
|
+
default: {}
|
186
|
+
},
|
187
|
+
/**
|
188
|
+
* show an icon (if exists) in front of label-text
|
189
|
+
*/
|
190
|
+
showLabelIcons: {
|
191
|
+
type: Boolean,
|
192
|
+
default: true
|
193
|
+
},
|
194
|
+
/**
|
195
|
+
* show a label-text for each entry
|
196
|
+
*/
|
197
|
+
showLabelTexts: {
|
198
|
+
type: Boolean,
|
199
|
+
default: false
|
200
|
+
},
|
201
|
+
linkGoogleMaps: {
|
202
|
+
type: Boolean,
|
203
|
+
default: false
|
204
|
+
}
|
205
|
+
},
|
206
|
+
methods: {
|
207
|
+
vCardClass(entry) {
|
208
|
+
if (entry.type === 'company') {
|
209
|
+
return "org"
|
210
|
+
}
|
211
|
+
if (entry.type === "address") {
|
212
|
+
if (entry.streetNo) {
|
213
|
+
return "street-address"
|
214
|
+
}
|
215
|
+
if (entry.zip) {
|
216
|
+
return "postal-code"
|
217
|
+
}
|
218
|
+
if (entry.city) {
|
219
|
+
return "locality"
|
220
|
+
}
|
221
|
+
if (entry.country) {
|
222
|
+
return "country-name"
|
223
|
+
}
|
224
|
+
}
|
225
|
+
return null
|
226
|
+
},
|
227
|
+
inputType(entry) {
|
228
|
+
if (entry.type === "phone") {
|
229
|
+
return "tel"
|
230
|
+
} else if (entry.type === "email") {
|
231
|
+
return "email"
|
232
|
+
} else if (entry.type === "url") {
|
233
|
+
return "url"
|
234
|
+
}
|
235
|
+
return "text"
|
236
|
+
},
|
237
|
+
locateAddress(entry) {
|
238
|
+
return "https://www.google.com/maps/place/" + entry.streetNo + ", " + entry.zip + " " + entry.city
|
239
|
+
},
|
240
|
+
getHref(entry) {
|
241
|
+
if (entry.type === "phone") {
|
242
|
+
return "tel:" + entry.href
|
243
|
+
}
|
244
|
+
if (entry.type === "email") {
|
245
|
+
return "mailto:" + entry.href
|
246
|
+
}
|
247
|
+
if (entry.type === "url") {
|
248
|
+
return entry.href
|
249
|
+
}
|
250
|
+
return null
|
251
|
+
},
|
252
|
+
addHandlerProvider() {
|
253
|
+
const itemStructure = {
|
254
|
+
"type": "default",
|
255
|
+
"iconClass": "icon-mail",
|
256
|
+
"data": "Your data",
|
257
|
+
"labelText": "Labeltext",
|
258
|
+
"tooltip": "Tooltip",
|
259
|
+
"href": "#"
|
260
|
+
}
|
261
|
+
return updateHandlerProvider(this, {
|
262
|
+
item() {
|
263
|
+
return itemStructure
|
264
|
+
}
|
265
|
+
})
|
266
|
+
},
|
267
|
+
updateHandlerProvider() {
|
268
|
+
const addressData = this.editableAddressEntry
|
269
|
+
return updateHandlerProvider(this, {
|
270
|
+
update(props) {
|
271
|
+
if (typeof addressData === "object") {
|
272
|
+
Object.entries(addressData).forEach(([name, value]) => props[name] = value)
|
273
|
+
} else {
|
274
|
+
if (props.href == null) {
|
275
|
+
props.data = addressData
|
276
|
+
} else {
|
277
|
+
props.href = addressData
|
278
|
+
}
|
279
|
+
}
|
280
|
+
}
|
281
|
+
})
|
282
|
+
}
|
283
|
+
},
|
284
|
+
watch: {
|
285
|
+
addressEntry: {
|
286
|
+
handler() {
|
287
|
+
// check if entry 'address' to create object
|
288
|
+
if (this.addressEntry.type === "address") {
|
289
|
+
this.editableAddressEntry = {
|
290
|
+
streetNo: this.addressEntry.streetNo,
|
291
|
+
zip: this.addressEntry.zip,
|
292
|
+
city: this.addressEntry.city,
|
293
|
+
miscInfo: this.addressEntry.miscInfo,
|
294
|
+
country: this.addressEntry.country
|
295
|
+
}
|
296
|
+
// for each other entry assign data or href
|
297
|
+
} else {
|
298
|
+
this.editableAddressEntry = (this.addressEntry.href == null ? this.addressEntry.data : this.addressEntry.href) || ""
|
299
|
+
}
|
300
|
+
},
|
301
|
+
immediate: true,
|
302
|
+
deep: true
|
303
|
+
}
|
304
|
+
}
|
305
|
+
}
|
306
|
+
</script>
|
@@ -1,6 +1,7 @@
|
|
1
1
|
<template>
|
2
2
|
<div class="cmd-box-wrapper">
|
3
|
-
<div
|
3
|
+
<div v-if="cmdHeadline.headlineText || allowUserToToggleOrientation || allowTogglingCollapsingBoxes"
|
4
|
+
class="flex-container headline-wrapper">
|
4
5
|
<!-- begin CmdHeadline -->
|
5
6
|
<CmdHeadline v-if="cmdHeadline.headlineText" v-bind="cmdHeadline" />
|
6
7
|
<!-- end CmdHeadline -->
|
@@ -18,11 +19,18 @@
|
|
18
19
|
</a>
|
19
20
|
</div>
|
20
21
|
</div>
|
21
|
-
<div :class="[
|
22
|
+
<div :class="[
|
23
|
+
useFlexbox ? 'flex-container' : 'grid-container-create-columns',
|
24
|
+
{
|
25
|
+
'no-gap': !useGap,
|
26
|
+
'row-view': rowView,
|
27
|
+
'stretch-boxes-vertically': stretchBoxesVertically
|
28
|
+
}
|
29
|
+
]">
|
22
30
|
<slot
|
23
31
|
:collapsingBoxesOpen="collapsingBoxesOpen"
|
24
32
|
:boxToggled="boxToggled"
|
25
|
-
:
|
33
|
+
:boxIsOpen="boxIsOpen"
|
26
34
|
:rowView="rowView"
|
27
35
|
@toggleCollapse="boxIsToggled"
|
28
36
|
>
|
@@ -38,10 +46,26 @@ export default {
|
|
38
46
|
return {
|
39
47
|
rowView: this.useRowViewAsDefault,
|
40
48
|
collapsingBoxesOpen: true,
|
41
|
-
currentOpenBox:
|
49
|
+
currentOpenBox: []
|
42
50
|
}
|
43
51
|
},
|
44
52
|
props: {
|
53
|
+
/**
|
54
|
+
* give list of box-indices that should be open by default
|
55
|
+
*
|
56
|
+
* allowMultipleExpandedBoxes-property must be activated if more than one box should be open by default
|
57
|
+
*/
|
58
|
+
openBoxesByDefault: {
|
59
|
+
type: Array,
|
60
|
+
required: false
|
61
|
+
},
|
62
|
+
/**
|
63
|
+
* activate if a gap between boxes should be used
|
64
|
+
*/
|
65
|
+
useGap: {
|
66
|
+
type: Boolean,
|
67
|
+
default: false
|
68
|
+
},
|
45
69
|
/**
|
46
70
|
* activate if boxes should be arranged vertically (each box is a row) by default
|
47
71
|
*/
|
@@ -174,6 +198,9 @@ export default {
|
|
174
198
|
}
|
175
199
|
},
|
176
200
|
methods: {
|
201
|
+
boxIsOpen(index) {
|
202
|
+
return this.currentOpenBox.includes(index)
|
203
|
+
},
|
177
204
|
boxIsToggled(event) {
|
178
205
|
alert(event)
|
179
206
|
},
|
@@ -201,10 +228,31 @@ export default {
|
|
201
228
|
this.collapsingBoxesOpen = !this.collapsingBoxesOpen
|
202
229
|
},
|
203
230
|
boxToggled(boxIndex, open) {
|
204
|
-
this.
|
231
|
+
if(this.allowMultipleExpandedBoxes) {
|
232
|
+
if(open) {
|
233
|
+
this.currentOpenBox.push(boxIndex)
|
234
|
+
} else {
|
235
|
+
// remove boxIndex from array to close specific box
|
236
|
+
let position = this.currentOpenBox.indexOf(boxIndex)
|
237
|
+
this.currentOpenBox.splice(position, 1)
|
238
|
+
}
|
239
|
+
} else {
|
240
|
+
this.currentOpenBox = []
|
241
|
+
|
242
|
+
// add current boxIndex to array to open specific box
|
243
|
+
if(open) {
|
244
|
+
this.currentOpenBox.push(boxIndex)
|
245
|
+
}
|
246
|
+
}
|
205
247
|
}
|
206
248
|
},
|
207
249
|
watch: {
|
250
|
+
openBoxesByDefault: {
|
251
|
+
handler() {
|
252
|
+
this.currentOpenBox = [...this.openBoxesByDefault || []]
|
253
|
+
},
|
254
|
+
immediate: true
|
255
|
+
},
|
208
256
|
useRowViewAsDefault: {
|
209
257
|
handler() {
|
210
258
|
this.oneBoxPerRow = this.useRowViewAsDefault
|
@@ -75,7 +75,6 @@
|
|
75
75
|
<div v-else-if="fancyBoxContent" class="content" v-html="fancyBoxContent"></div>
|
76
76
|
<div v-else-if="fancyBoxElements" class="content"></div>
|
77
77
|
<div v-else-if="fancyBoxGallery" class="content">
|
78
|
-
|
79
78
|
<!-- begin CmdSlideButton -->
|
80
79
|
<CmdSlideButton @click.prevent="showPrevItem" slideButtonType="prev"/>
|
81
80
|
<!-- end CmdSlideButton -->
|
@@ -174,11 +173,11 @@ const FancyBox = defineComponent({
|
|
174
173
|
},
|
175
174
|
props: {
|
176
175
|
/**
|
177
|
-
* sets aria-label-text on component
|
176
|
+
* sets default aria-label-text on component
|
178
177
|
*
|
179
178
|
* @requiredForAccessibility: true
|
180
179
|
*/
|
181
|
-
|
180
|
+
defaultAriaLabelText: {
|
182
181
|
type: String,
|
183
182
|
required: true
|
184
183
|
},
|
@@ -201,7 +200,7 @@ const FancyBox = defineComponent({
|
|
201
200
|
*/
|
202
201
|
showSubmitButtons: {
|
203
202
|
type: Boolean,
|
204
|
-
default:
|
203
|
+
default: false
|
205
204
|
},
|
206
205
|
/**
|
207
206
|
* options to show at top (closeIcon, printButtons)
|
@@ -348,6 +347,13 @@ const FancyBox = defineComponent({
|
|
348
347
|
fancyBoxItem.src = this.fancyBoxImageUrl
|
349
348
|
}
|
350
349
|
return fancyBoxItem
|
350
|
+
},
|
351
|
+
ariaLabelText() {
|
352
|
+
if(this.fancyBoxGallery?.length) {
|
353
|
+
return this.fancyBoxGallery[this.index].figcaption.text
|
354
|
+
} else {
|
355
|
+
return this.defaultAriaLabelText
|
356
|
+
}
|
351
357
|
}
|
352
358
|
},
|
353
359
|
methods: {
|
@@ -513,6 +519,7 @@ export default FancyBox
|
|
513
519
|
|
514
520
|
img {
|
515
521
|
display: block;
|
522
|
+
margin: 0 auto;
|
516
523
|
}
|
517
524
|
|
518
525
|
figcaption {
|
@@ -520,6 +527,26 @@ export default FancyBox
|
|
520
527
|
}
|
521
528
|
}
|
522
529
|
|
530
|
+
.inner-thumbnail-wrapper li {
|
531
|
+
figure {
|
532
|
+
opacity: 0.8;
|
533
|
+
}
|
534
|
+
|
535
|
+
&.active {
|
536
|
+
figure {
|
537
|
+
opacity: 1;
|
538
|
+
}
|
539
|
+
|
540
|
+
img {
|
541
|
+
border-color: var(--hyperlink-color-highlighted);
|
542
|
+
}
|
543
|
+
|
544
|
+
a {
|
545
|
+
color: var(--hyperlink-color-highlighted);
|
546
|
+
}
|
547
|
+
}
|
548
|
+
}
|
549
|
+
|
523
550
|
> header {
|
524
551
|
justify-content: space-between;
|
525
552
|
|
@@ -4,8 +4,37 @@
|
|
4
4
|
<fieldset class="flex-container">
|
5
5
|
<legend :class="{hidden : !showLegend}">{{ textLegend }}</legend>
|
6
6
|
<!-- begin default-slot-content -->
|
7
|
-
<slot></slot>
|
7
|
+
<slot v-if="useSlot"></slot>
|
8
8
|
<!-- end default-slot-content -->
|
9
|
+
|
10
|
+
<!-- begin loop for formElements -->
|
11
|
+
<CmdFormElement
|
12
|
+
v-else
|
13
|
+
v-for="(item, index) in formElements"
|
14
|
+
:key="index"
|
15
|
+
:element="item.element || 'input'"
|
16
|
+
:type="item.type || 'text'"
|
17
|
+
:name="item.name"
|
18
|
+
:class="item.htmlClass"
|
19
|
+
:id="item.id || createHtmlId()"
|
20
|
+
v-model="formValues[item.name]"
|
21
|
+
:inputValue="item.inputValue"
|
22
|
+
:fieldIconClass="item.innerIconClass"
|
23
|
+
:selectOptions="item.selectOptions"
|
24
|
+
:labelText="item.labelText"
|
25
|
+
:placeholder="item.placeholder"
|
26
|
+
:required="item.required"
|
27
|
+
:disabled="item.disabled"
|
28
|
+
:autocomplete="item.autocomplete"
|
29
|
+
:minlength="item.minlength"
|
30
|
+
:maxlength="item.maxlength"
|
31
|
+
:nativeButton="item.nativeButton"
|
32
|
+
/>
|
33
|
+
<!-- end loop for formElements -->
|
34
|
+
<button v-if="submitButton" class="button" type="submit">
|
35
|
+
<span v-if="submitButton.iconClass" :class="submitButton.iconClass"></span>
|
36
|
+
<span v-if="submitButton.text">{{ submitButton.text }}</span>
|
37
|
+
</button>
|
9
38
|
</fieldset>
|
10
39
|
|
11
40
|
<!-- begin button-row-slot-content -->
|
@@ -20,15 +49,32 @@
|
|
20
49
|
</template>
|
21
50
|
|
22
51
|
<script>
|
52
|
+
import {createHtmlId} from "@"
|
53
|
+
|
23
54
|
export default {
|
24
55
|
name: "CmdForm",
|
25
56
|
emits: ["submit"],
|
26
57
|
data(){
|
27
58
|
return {
|
28
|
-
errorOccurred: false
|
59
|
+
errorOccurred: false,
|
60
|
+
formValues: {}
|
29
61
|
}
|
30
62
|
},
|
31
63
|
props: {
|
64
|
+
/**
|
65
|
+
* activate if form-elements should be given by slot
|
66
|
+
*/
|
67
|
+
useSlot: {
|
68
|
+
type: Boolean,
|
69
|
+
default: true
|
70
|
+
},
|
71
|
+
/**
|
72
|
+
* define form-elements by given array
|
73
|
+
*/
|
74
|
+
formElements: {
|
75
|
+
type: Array,
|
76
|
+
required: false
|
77
|
+
},
|
32
78
|
/**
|
33
79
|
* deactivate if browser-validation should be used
|
34
80
|
*/
|
@@ -73,20 +119,68 @@ export default {
|
|
73
119
|
textLegend: {
|
74
120
|
type: String,
|
75
121
|
required: false
|
122
|
+
},
|
123
|
+
/**
|
124
|
+
* submitbutton to submit all formdata
|
125
|
+
*/
|
126
|
+
submitButton: {
|
127
|
+
type: Object,
|
128
|
+
default() {
|
129
|
+
return {
|
130
|
+
iconClass: "icon-check",
|
131
|
+
text: "Submit"
|
132
|
+
}
|
133
|
+
}
|
76
134
|
}
|
77
135
|
},
|
78
136
|
methods: {
|
137
|
+
createHtmlId,
|
138
|
+
submitFormData(event) {
|
139
|
+
// fill formdata with names and value
|
140
|
+
let formdata = {}
|
141
|
+
this.formElements.forEach((element) => {
|
142
|
+
formdata[element.name] = this.formValues[element.name]
|
143
|
+
})
|
144
|
+
|
145
|
+
this.$emit("submit", {originalEvent: event, formdata: formdata})
|
146
|
+
},
|
79
147
|
onSubmit(event) {
|
80
148
|
if(this.useValidation) {
|
81
|
-
event.preventDefault()
|
82
149
|
if(event.target.checkValidity()) {
|
83
150
|
this.errorOccurred = false
|
84
|
-
this
|
151
|
+
this.submitFormData(event)
|
85
152
|
} else {
|
153
|
+
event.preventDefault()
|
86
154
|
this.errorOccurred = true
|
87
155
|
}
|
156
|
+
} else {
|
157
|
+
this.submitFormData(event)
|
88
158
|
}
|
89
159
|
}
|
160
|
+
},
|
161
|
+
watch: {
|
162
|
+
formElements: {
|
163
|
+
handler() {
|
164
|
+
this.formValues = {}
|
165
|
+
|
166
|
+
this.formElements?.forEach(element => {
|
167
|
+
if(element.type === "checkbox") {
|
168
|
+
// create array if element is a checkbox (to contain several values)
|
169
|
+
if(!this.formValues[element.name]) {
|
170
|
+
this.formValues[element.name] = []
|
171
|
+
}
|
172
|
+
|
173
|
+
if(element.value != null) {
|
174
|
+
this.formValues[element.name].push(element.value)
|
175
|
+
}
|
176
|
+
} else {
|
177
|
+
this.formValues[element.name] = element.value ?? ""
|
178
|
+
}
|
179
|
+
})
|
180
|
+
},
|
181
|
+
immediate: true,
|
182
|
+
deep: true
|
183
|
+
}
|
90
184
|
}
|
91
185
|
}
|
92
186
|
</script>
|
@@ -216,7 +216,7 @@
|
|
216
216
|
<!-- end searchfield -->
|
217
217
|
|
218
218
|
<!-- begin button -->
|
219
|
-
<button v-else class="button" v-bind="buttonAttrs">
|
219
|
+
<button v-else-if="element === 'button'" class="button" v-bind="buttonAttrs" @click="submit">
|
220
220
|
<!-- begin CmdIcon -->
|
221
221
|
<CmdIcon
|
222
222
|
v-if="nativeButton?.icon?.show && (nativeButton?.icon?.position === 'before' || !nativeButton?.icon?.position)"
|
@@ -825,6 +825,10 @@ export default {
|
|
825
825
|
if(this.$refs.tooltip) {
|
826
826
|
this.$refs.tooltip.hideTooltip()
|
827
827
|
}
|
828
|
+
},
|
829
|
+
// (submit-)button is clicked
|
830
|
+
submit(event) {
|
831
|
+
this.$emit("submit", event)
|
828
832
|
}
|
829
833
|
},
|
830
834
|
watch: {
|