comand-component-library 3.3.83 → 3.3.85
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/comand-component-library.js +5630 -3936
- 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 +150 -21
- 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: {
|