comand-component-library 3.1.43 → 3.1.46

Sign up to get free protection for your applications and to get access to all the features.
Files changed (236) hide show
  1. package/dist/comand-component-library.css +1 -1
  2. package/dist/comand-component-library.umd.min.js +1 -1
  3. package/package.json +47 -40
  4. package/src/App.vue +379 -136
  5. package/src/ComponentDocumentation.vue +156 -0
  6. package/src/ComponentLibraryHelp.vue +20 -0
  7. package/src/assets/data/accordion.json +21 -24
  8. package/src/assets/data/address-data.json +34 -0
  9. package/src/assets/data/bank-account-data.json +22 -0
  10. package/src/assets/data/box-product.json +14 -4
  11. package/src/assets/data/box-user.json +48 -22
  12. package/src/assets/data/breadcrumbs.json +11 -3
  13. package/src/assets/data/cookie-disclaimer.json +4 -4
  14. package/src/assets/data/fake-select-colors.json +4 -0
  15. package/src/assets/data/fake-select-countries.json +12 -12
  16. package/src/assets/data/fake-select-filter-options.json +14 -0
  17. package/src/assets/data/fake-select-options-with-icons.json +6 -12
  18. package/src/assets/data/fake-select-options.json +3 -3
  19. package/src/assets/data/list-of-links-section-anchors.json +23 -0
  20. package/src/assets/data/list-of-links-top-header-navigation.json +20 -0
  21. package/src/assets/data/list-of-links.json +42 -0
  22. package/src/assets/data/main-navigation.json +48 -0
  23. package/src/assets/data/multistep-form-progress-bar.json +33 -0
  24. package/src/assets/data/select-options.json +4 -0
  25. package/src/assets/data/{share-buttons.json → share-buttons-page-by-json.json} +8 -8
  26. package/src/assets/data/share-buttons-page-by-property.json +30 -0
  27. package/src/assets/data/switch-language.json +20 -0
  28. package/src/assets/data/table-large.json +1 -1
  29. package/src/assets/data/table-small.json +1 -1
  30. package/src/assets/styles/global-styles.scss +43 -14
  31. package/src/assets/styles/transitions.scss +21 -1
  32. package/src/components/CmdAccordion.vue +43 -42
  33. package/src/components/CmdAddressData.vue +124 -56
  34. package/src/components/CmdBackToTopButton.vue +3 -3
  35. package/src/components/CmdBankAccountData.vue +104 -0
  36. package/src/components/CmdBox.vue +253 -56
  37. package/src/components/CmdBoxSiteSearch.vue +138 -39
  38. package/src/components/CmdBoxWrapper.vue +206 -0
  39. package/src/components/CmdBreadcrumbs.vue +29 -13
  40. package/src/components/CmdCompanyLogo.vue +6 -4
  41. package/src/components/CmdCookieDisclaimer.vue +99 -75
  42. package/src/components/CmdCopyrightInformation.vue +1 -1
  43. package/src/components/CmdCustomHeadline.vue +93 -0
  44. package/src/components/CmdFakeSelect.vue +330 -66
  45. package/src/components/CmdFancyBox.vue +47 -33
  46. package/src/components/CmdForm.vue +107 -0
  47. package/src/components/CmdFormElement.vue +528 -83
  48. package/src/components/CmdFormFilters.vue +25 -11
  49. package/src/components/CmdGoogleMaps.vue +9 -3
  50. package/src/components/CmdImageGallery.vue +28 -5
  51. package/src/components/CmdImageZoom.vue +9 -1
  52. package/src/components/CmdListOfLinks.vue +169 -0
  53. package/src/components/CmdLoginForm.vue +146 -66
  54. package/src/components/CmdMainNavigation.vue +140 -42
  55. package/src/components/CmdMultipleSwitch.vue +33 -2
  56. package/src/components/CmdMultistepFormProgressBar.vue +60 -10
  57. package/src/components/CmdOpeningHours.vue +36 -10
  58. package/src/components/CmdPager.vue +7 -5
  59. package/src/components/CmdProgressBar.vue +21 -4
  60. package/src/components/CmdShareButtons.vue +64 -9
  61. package/src/components/CmdSiteHeader.vue +25 -12
  62. package/src/components/CmdSlideButton.vue +5 -2
  63. package/src/components/CmdSlideshow.vue +23 -7
  64. package/src/components/CmdSwitchButton.vue +15 -6
  65. package/src/components/CmdSwitchLanguage.vue +18 -10
  66. package/src/components/CmdSystemMessage.vue +30 -17
  67. package/src/components/CmdTable.vue +15 -7
  68. package/src/components/CmdTabs.vue +43 -3
  69. package/src/components/CmdThumbnailScroller.vue +22 -6
  70. package/src/components/CmdTooltip.vue +184 -11
  71. package/src/components/CmdUploadForm.vue +830 -176
  72. package/src/components/CmdWidthLimitationWrapper.vue +9 -6
  73. package/src/composables/event.js +8 -0
  74. package/src/composables/scrollspy.js +52 -0
  75. package/src/directives/focus.js +19 -0
  76. package/src/directives/telephone.js +1 -1
  77. package/src/documentation/commonProps.js +6 -0
  78. package/src/documentation/components/ComponentCode.vue +50 -0
  79. package/src/documentation/components/ComponentProperties.vue +237 -0
  80. package/src/documentation/components/ExampleSectionWrapper.vue +46 -0
  81. package/src/documentation/components/ViewCodeData.vue +113 -0
  82. package/src/documentation/data/CmdAccordionHelp.js +22 -0
  83. package/src/documentation/data/CmdAddressDataHelp.js +17 -0
  84. package/src/documentation/data/CmdBackToTopButtonHelp.js +3 -0
  85. package/src/documentation/data/CmdBankAccountDataHelp.js +8 -0
  86. package/src/documentation/data/CmdBoxHelp.js +45 -0
  87. package/src/documentation/data/CmdBoxSiteSearchHelp.js +11 -0
  88. package/src/documentation/data/CmdBreadcrumbsHelp.js +6 -0
  89. package/src/documentation/data/CmdCompanyLogoHelp.js +8 -0
  90. package/src/documentation/data/CmdCookieDisclaimerHelp.js +9 -0
  91. package/src/documentation/data/CmdCopyrightInformation.js +2 -0
  92. package/src/documentation/data/CmdCustomHeadlineHelp.js +8 -0
  93. package/src/documentation/data/CmdFakeSelectHelp.js +60 -0
  94. package/src/documentation/data/CmdFancyBoxHelp.js +7 -0
  95. package/src/documentation/data/CmdFooterNavigationHelp.js +5 -0
  96. package/src/documentation/data/CmdFormElementHelp.js +189 -0
  97. package/src/documentation/data/CmdFormFiltersHelp.js +6 -0
  98. package/src/documentation/data/CmdFormHelp.js +10 -0
  99. package/src/documentation/data/CmdGoogleMapsHelp.js +5 -0
  100. package/src/documentation/data/CmdImageGalleryHelp.js +5 -0
  101. package/src/documentation/data/CmdImageZoomHelp.js +6 -0
  102. package/src/documentation/data/CmdListOfLinksHelp.js +24 -0
  103. package/src/documentation/data/CmdLoginFormHelp.js +6 -0
  104. package/src/documentation/data/CmdMainNavigationHelp.js +7 -0
  105. package/src/documentation/data/CmdMultistepFormProgressBarHelp.js +6 -0
  106. package/src/documentation/data/CmdOpeningHoursHelp.js +10 -0
  107. package/src/documentation/data/CmdPagerHelp.js +7 -0
  108. package/src/documentation/data/CmdProgressBarHelp.js +13 -0
  109. package/src/documentation/data/CmdShareButtonsHelp.js +13 -0
  110. package/src/documentation/data/CmdSiteHeaderHelp.js +21 -0
  111. package/src/documentation/data/CmdSlideButtonHelp.js +10 -0
  112. package/src/documentation/data/CmdSlideshowHelp.js +7 -0
  113. package/src/documentation/data/CmdSwitchLanguageHelp.js +6 -0
  114. package/src/documentation/data/CmdSystemMessageHelp.js +32 -0
  115. package/src/documentation/data/CmdTableHelp.js +14 -0
  116. package/src/documentation/data/CmdTabsHelp.js +10 -0
  117. package/src/documentation/data/CmdThumbnailScrollerHelp.js +5 -0
  118. package/src/documentation/data/CmdTooltipHelp.js +13 -0
  119. package/src/documentation/data/CmdUploadFormHelp.js +17 -0
  120. package/src/documentation/data/CmdWidthLimitationWrapperHelp.js +7 -0
  121. package/src/documentation/data/componentsDescription.json +158 -0
  122. package/src/documentation/generated/CmdAccordionPropertyDescriptions.json +57 -0
  123. package/src/documentation/generated/CmdAddressDataPropertyDescriptions.json +32 -0
  124. package/src/documentation/generated/CmdBackToTopButtonPropertyDescriptions.json +12 -0
  125. package/src/documentation/generated/CmdBankAccountDataPropertyDescriptions.json +34 -0
  126. package/src/documentation/generated/CmdBoxPropertyDescriptions.json +91 -0
  127. package/src/documentation/generated/CmdBoxSiteSearchPropertyDescriptions.json +41 -0
  128. package/src/documentation/generated/CmdBoxWrapperPropertyDescriptions.json +47 -0
  129. package/src/documentation/generated/CmdBreadcrumbsPropertyDescriptions.json +17 -0
  130. package/src/documentation/generated/CmdCompanyLogoPropertyDescriptions.json +27 -0
  131. package/src/documentation/generated/CmdCookieDisclaimerPropertyDescriptions.json +22 -0
  132. package/src/documentation/generated/CmdCustomHeadlinePropertyDescriptions.json +22 -0
  133. package/src/documentation/generated/CmdFakeSelectPropertyDescriptions.json +79 -0
  134. package/src/documentation/generated/CmdFancyBoxPropertyDescriptions.json +62 -0
  135. package/src/documentation/generated/CmdFooterNavigationPropertyDescriptions.json +17 -0
  136. package/src/documentation/generated/CmdFormElementPropertyDescriptions.json +178 -0
  137. package/src/documentation/generated/CmdFormFiltersPropertyDescriptions.json +32 -0
  138. package/src/documentation/generated/CmdFormPropertyDescriptions.json +40 -0
  139. package/src/documentation/generated/CmdGoogleMapsPropertyDescriptions.json +7 -0
  140. package/src/documentation/generated/CmdImageGalleryPropertyDescriptions.json +22 -0
  141. package/src/documentation/generated/CmdImageZoomPropertyDescriptions.json +12 -0
  142. package/src/documentation/generated/CmdListOfLinksPropertyDescriptions.json +60 -0
  143. package/src/documentation/generated/CmdLoginFormPropertyDescriptions.json +90 -0
  144. package/src/documentation/generated/CmdMainNavigationPropertyDescriptions.json +62 -0
  145. package/src/documentation/generated/CmdMultipleSwitchPropertyDescriptions.json +52 -0
  146. package/src/documentation/generated/CmdMultistepFormProgressBarPropertyDescriptions.json +17 -0
  147. package/src/documentation/generated/CmdOpeningHoursPropertyDescriptions.json +42 -0
  148. package/src/documentation/generated/CmdPagerPropertyDescriptions.json +37 -0
  149. package/src/documentation/generated/CmdProgressBarPropertyDescriptions.json +32 -0
  150. package/src/documentation/generated/CmdShareButtonsPropertyDescriptions.json +34 -0
  151. package/src/documentation/generated/CmdSiteHeaderPropertyDescriptions.json +27 -0
  152. package/src/documentation/generated/CmdSlideButtonPropertyDescriptions.json +25 -0
  153. package/src/documentation/generated/CmdSlideshowPropertyDescriptions.json +42 -0
  154. package/src/documentation/generated/CmdSwitchButtonPropertyDescriptions.json +79 -0
  155. package/src/documentation/generated/CmdSwitchLanguagePropertyDescriptions.json +7 -0
  156. package/src/documentation/generated/CmdSystemMessagePropertyDescriptions.json +40 -0
  157. package/src/documentation/generated/CmdTablePropertyDescriptions.json +62 -0
  158. package/src/documentation/generated/CmdTabsPropertyDescriptions.json +27 -0
  159. package/src/documentation/generated/CmdThumbnailScrollerPropertyDescriptions.json +32 -0
  160. package/src/documentation/generated/CmdTooltipPropertyDescriptions.json +17 -0
  161. package/src/documentation/generated/CmdUploadFormPropertyDescriptions.json +90 -0
  162. package/src/documentation/generated/CmdWidthLimitationWrapperPropertyDescriptions.json +41 -0
  163. package/src/documentation/generated/frameworkIcons.json +730 -0
  164. package/src/documentation/generated/logosIcons.json +110 -0
  165. package/src/documentation/tabs.js +46 -0
  166. package/src/documentation/views/ContainerPage.vue +237 -0
  167. package/src/documentation/views/HelpHome.vue +13 -0
  168. package/src/documentation/views/IconFont.vue +80 -0
  169. package/src/documentation/views/components/CmdAccordionHelp.vue +78 -0
  170. package/src/documentation/views/components/CmdAddressDataHelp.vue +65 -0
  171. package/src/documentation/views/components/CmdBackToTopButtonHelp.vue +62 -0
  172. package/src/documentation/views/components/CmdBankAccountDataHelp.vue +88 -0
  173. package/src/documentation/views/components/CmdBoxHelp.vue +137 -0
  174. package/src/documentation/views/components/CmdBoxSiteSearchHelp.vue +60 -0
  175. package/src/documentation/views/components/CmdBoxWrapperHelp.vue +111 -0
  176. package/src/documentation/views/components/CmdBreadcrumbsHelp.vue +51 -0
  177. package/src/documentation/views/components/CmdCompanyLogoHelp.vue +48 -0
  178. package/src/documentation/views/components/CmdCookieDisclaimerHelp.vue +105 -0
  179. package/src/documentation/views/components/CmdCustomHeadlineHelp.vue +53 -0
  180. package/src/documentation/views/components/CmdFakeSelectHelp.vue +175 -0
  181. package/src/documentation/views/components/CmdFancyBoxHelp.vue +79 -0
  182. package/src/documentation/views/components/CmdFormElementHelp.vue +412 -0
  183. package/src/documentation/views/components/CmdFormFiltersHelp.vue +69 -0
  184. package/src/documentation/views/components/CmdFormHelp.vue +41 -0
  185. package/src/documentation/views/components/CmdGoogleMapsHelp.vue +55 -0
  186. package/src/documentation/views/components/CmdImageGalleryHelp.vue +46 -0
  187. package/src/documentation/views/components/CmdImageZoomHelp.vue +34 -0
  188. package/src/documentation/views/components/CmdListOfLinksHelp.vue +64 -0
  189. package/src/documentation/views/components/CmdLoginFormHelp.vue +117 -0
  190. package/src/documentation/views/components/CmdMainNavigationHelp.vue +94 -0
  191. package/src/documentation/views/components/CmdMultistepFormProgressBarHelp.vue +49 -0
  192. package/src/documentation/views/components/CmdOpeningHoursHelp.vue +49 -0
  193. package/src/documentation/views/components/CmdPagerHelp.vue +57 -0
  194. package/src/documentation/views/components/CmdProgressBarHelp.vue +47 -0
  195. package/src/documentation/views/components/CmdShareButtonsHelp.vue +65 -0
  196. package/src/documentation/views/components/CmdSiteHeaderHelp.vue +72 -0
  197. package/src/documentation/views/components/CmdSlideButtonHelp.vue +90 -0
  198. package/src/documentation/views/components/CmdSlideshowHelp.vue +60 -0
  199. package/src/documentation/views/components/CmdSwitchLanguageHelp.vue +64 -0
  200. package/src/documentation/views/components/CmdSystemMessageHelp.vue +86 -0
  201. package/src/documentation/views/components/CmdTableHelp.vue +84 -0
  202. package/src/documentation/views/components/CmdTabsHelp.vue +52 -0
  203. package/src/documentation/views/components/CmdThumbnailScrollerHelp.vue +50 -0
  204. package/src/documentation/views/components/CmdTooltipHelp.vue +59 -0
  205. package/src/documentation/views/components/CmdUploadFormHelp.vue +59 -0
  206. package/src/documentation/views/components/CmdWidthLimitationWrapperHelp.vue +46 -0
  207. package/src/index.js +6 -3
  208. package/src/main.js +25 -15
  209. package/src/mixins/CmdAddressData/DefaultMessageProperties.js +17 -0
  210. package/src/mixins/CmdBox/DefaultMessageProperties.js +10 -0
  211. package/src/mixins/CmdFakeSelect/DefaultMessageProperties.js +9 -0
  212. package/src/mixins/CmdFormElement/DefaultMessageProperties.js +9 -0
  213. package/src/mixins/CmdImageGallery/DefaultMessageProperties.js +9 -0
  214. package/src/mixins/CmdSiteSearch/DefaultMessageProperties.js +14 -0
  215. package/src/mixins/CmdUploadForm/DefaultMessageProperties.js +53 -0
  216. package/src/mixins/FieldValidation.js +220 -0
  217. package/src/mixins/GlobalDefaultMessageProperties.js +15 -0
  218. package/src/mixins/I18n.js +56 -0
  219. package/src/mixins/Tooltip.js +26 -0
  220. package/src/router/index.js +67 -0
  221. package/src/utilities.js +3 -6
  222. package/src/utils/GetFileExtension.js +15 -0
  223. package/src/utils/common.js +6 -0
  224. package/src/utils/dom.js +8 -0
  225. package/src/utils/globalSequence.js +13 -0
  226. package/src/utils/string.js +8 -0
  227. package/src/assets/data/address.json +0 -13
  228. package/src/assets/data/footer-navigation.json +0 -38
  229. package/src/assets/data/languages.json +0 -31
  230. package/src/assets/data/multisteps.json +0 -27
  231. package/src/assets/data/navigation.json +0 -47
  232. package/src/assets/data/pager.json +0 -11
  233. package/src/assets/data/top-header-navigation.json +0 -27
  234. package/src/components/CmdFooterNavigation.vue +0 -71
  235. package/src/components/CmdMainHeadline.vue +0 -75
  236. package/src/components/CmdTopHeaderNavigation.vue +0 -88
@@ -1,39 +1,83 @@
1
1
  <template>
2
2
  <label v-if="(element === 'input' || element === 'select' || element === 'textarea')"
3
+ :class="[
4
+ 'cmd-form-element',
5
+ validationStatus,
6
+ {
7
+ disabled: $attrs.disabled,
8
+ inline : displayLabelInline,
9
+ checked: isChecked,
10
+ 'toggle-switch-label': toggleSwitch,
11
+ colored: colored,
12
+ on: colored && isChecked,
13
+ off: colored && !isChecked,
14
+ 'has-state': validationStatus
15
+ }]"
3
16
  :for="id"
4
- :class="['cmd-form-element', status, {'inline' : displayLabelInline, 'checked': isChecked}]"
5
17
  ref="label">
6
- <!-- begin label (+ required) -->
18
+
19
+ <!-- begin label-text (+ required asterisk) -->
7
20
  <span v-if="labelText && $attrs.type !== 'checkbox' && $attrs.type !== 'radio'"
8
- :class="{'hidden': hideLabel}">
9
- <span>{{ labelText }}</span>
10
- <sup v-if="$attrs.required">*</sup>
11
- </span>
12
- <!-- end label (+ required) -->
21
+ :class="!showLabel ? 'hidden' : undefined">
22
+ <span>
23
+ {{ labelText }}<sup v-if="$attrs.required">*</sup>
24
+ </span>
25
+ <a v-if="$attrs.required || inputRequirements.length"
26
+ href="#"
27
+ @click.prevent
28
+ :class="getStatusIconClass"
29
+ :title="validationTooltip"
30
+ :aria-errormessage="getValidationMessage"
31
+ aria-live="assertive"
32
+ :id="tooltipId"
33
+ :role="validationStatus === 'error' ? 'alert' : 'dialog'">
34
+ </a>
35
+ </span>
36
+ <!-- end label-text (+ required asterisk) -->
13
37
 
14
38
  <!-- begin icon -->
15
- <span v-if="$attrs.type !== 'checkbox' && $attrs.type !== 'radio' && innerIconClass" class="place-inside"
16
- :class="[status, innerIconClass]"></span>
39
+ <span
40
+ v-if="
41
+ $attrs.type !== 'checkbox' &&
42
+ $attrs.type !== 'radio' &&
43
+ fieldIconClass
44
+ "
45
+ :class="['place-inside', fieldIconClass]"
46
+ ></span>
17
47
  <!-- end icon -->
18
48
 
19
49
  <!-- begin inputfield -->
20
50
  <template
21
51
  v-if="element === 'input' && $attrs.type !== 'checkbox' && $attrs.type !== 'radio' && $attrs.type !== 'search'">
22
52
  <input v-bind="$attrs"
23
- :id="id" :class="htmlClass"
53
+ :id="id"
54
+ :class="htmlClass"
24
55
  @focus="tooltip = true"
25
- @blur="tooltip = false"
56
+ @blur="onBlur"
26
57
  @input="onInput"
27
58
  @mouseover="datalistFocus"
28
- @change="$emit('change', $event)"
59
+ @keyup="checkForCapsLock"
29
60
  :autocomplete="datalist ? 'off' : 'on'"
30
61
  :list="datalist ? datalist.id : false"
31
- :disabled="status === 'disabled'"
32
- :value="value"
62
+ :value="modelValue"
63
+ :maxlength="$attrs.maxlength > 0 ? $attrs.maxlength : 255"
64
+ ref="input"
33
65
  />
34
66
  </template>
35
67
  <!-- end inputfield -->
36
68
 
69
+ <!-- begin show-password-icon -->
70
+ <a v-if="$attrs.type === 'password'"
71
+ href="#"
72
+ class="place-inside icon-visible"
73
+ @mousedown.prevent="showPassword"
74
+ @mouseup.prevent="hidePassword"
75
+ @mouseleave.prevent="hidePassword"
76
+ @click.prevent
77
+ title="Toggle password visibility">
78
+ </a>
79
+ <!-- end show-password-icon -->
80
+
37
81
  <!-- begin datalist -->
38
82
  <template v-if="datalist && datalist.options.length">
39
83
  <datalist :id="datalist.id">
@@ -46,19 +90,32 @@
46
90
  <template v-else-if="element === 'input' && ($attrs.type === 'checkbox' || $attrs.type === 'radio')">
47
91
  <input v-bind="$attrs"
48
92
  @change="onChange"
93
+ @blur="onBlur"
49
94
  :checked="isChecked"
95
+ :role="$attrs.type"
96
+ :aria-checked="isChecked"
50
97
  :value="inputValue"
51
- :class="[htmlClass, status, { 'replace-input-type': replaceInputType }]"
98
+ :class="[htmlClass, validationStatus, { 'replace-input-type': replaceInputType, 'toggle-switch': toggleSwitch }]"
52
99
  :id="id"
53
- :disabled="status === 'disabled'"
54
- :aria-invalid="status === 'error'"
100
+ :aria-invalid="validationStatus === 'error'"
55
101
  :aria-describedby="`status-message-${id}`"
56
102
  />
57
- <span v-if="labelText">
58
- <span>{{ labelText }}</span>
59
- <sup v-if="$attrs.required">*</sup>
60
- </span>
103
+
104
+ <!-- begin labels for toggle-switch -->
105
+ <span v-if="!(onLabel && offLabel)" :class="{ hidden: !showLabel }">
106
+ <span v-if="labelText">{{ labelText }}<sup v-if="$attrs.required">*</sup></span>
107
+ </span>
108
+ <template v-else-if="onLabel && offLabel">
109
+ <span v-if="labelText">
110
+ <span>{{ labelText }}<sup v-if="$attrs.required">*</sup></span>
111
+ </span>
112
+ <div class="toggle-switch switch-label">
113
+ <span class="label">{{ onLabel }}</span>
114
+ <span class="label">{{ offLabel }}</span>
115
+ </div>
116
+ </template>
61
117
  <slot v-else></slot>
118
+ <!-- end labels for toggle-switch -->
62
119
  </template>
63
120
  <!-- end checkbox and radiobutton -->
64
121
 
@@ -66,11 +123,10 @@
66
123
  <select v-if="element === 'select'"
67
124
  v-bind="$attrs"
68
125
  :id="id"
69
- :disabled="status === 'disabled'"
70
- @change="$emit('input', $event.target.value)"
71
- >
126
+ @blur="onBlur"
127
+ @change="$emit('update:modelValue', $event.target.value)">
72
128
  <option v-for="(option, index) in selectOptions" :key="index" :value="option.value"
73
- :selected="option.value === value">{{ option.text }}
129
+ :selected="option.value === modelValue">{{ option.text }}
74
130
  </option>
75
131
  </select>
76
132
  <!-- end selectbox -->
@@ -79,66 +135,124 @@
79
135
  <textarea v-if="element === 'textarea'"
80
136
  v-bind="$attrs"
81
137
  :id="id"
82
- :disabled="status === 'disabled'"
83
- :value="value"
138
+ :value="modelValue"
139
+ :maxlength="getMaxLength"
84
140
  @input="onInput"
85
141
  @focus="tooltip = true"
86
- @blur="tooltip = false">
142
+ @blur="onBlur">
87
143
  </textarea>
144
+ <span v-if="element === 'textarea' && showCharactersTextarea">{{ charactersTextarea }}</span>
88
145
  <!-- end textarea -->
89
146
 
90
- <!-- begin tooltip -->
91
- <CmdTooltip v-if="tooltip && tooltipText" :tooltipText="tooltipText"/>
92
- <!-- end tooltip -->
93
-
94
147
  <!-- begin searchfield -->
95
- <span v-else-if="element === 'input' && $attrs.type === 'search'" class="flex-container no-gap">
96
- <input v-bind="$attrs" :id="id" @input="onInput" :value="value"/>
97
- <button class="no-flex" type="button" :disabled="status === 'disabled'">
98
- <span class="icon-search"></span>
99
- </button>
100
- </span>
148
+ <span v-else-if="element === 'input' && $attrs.type === 'search'" class="search-field-wrapper flex-container no-gap">
149
+ <a v-if="iconDelete.show" href="#" @click.prevent="$emit('update:modelValue', '')" :class="iconDelete.iconClass" :title="iconDelete.tooltip"/>
150
+ <input
151
+ v-bind="$attrs"
152
+ :id="id"
153
+ @input="onInput"
154
+ :maxlength="$attrs.maxlength > 0 ? $attrs.maxlength : 255"
155
+ :value="modelValue"
156
+ />
157
+ <button v-if="showSearchButton" class="no-flex" type="button" :title="iconSearch.tooltip">
158
+ <span :class="iconSearch.iconClass"></span>
159
+ </button>
160
+ </span>
101
161
  <!-- end searchfield -->
102
162
  </label>
103
163
 
104
164
  <!-- begin button -->
105
- <button v-else class="button" v-bind="$attrs" :disabled="status === 'disabled'">
106
- <span v-if="buttonIcon.iconPosition === 'before'" :class="buttonIcon.iconClass"></span>
107
- <span v-if="buttonIcon.iconPosition">{{ buttonText }}</span>
165
+ <button v-else class="button" v-bind="buttonAttrs">
166
+ <span v-if="nativeButton?.icon?.show && (nativeButton?.icon?.position === 'before' || !nativeButton?.icon?.position)" :class="nativeButton?.icon?.iconClass"></span>
167
+ <span v-if="nativeButton?.icon && nativeButton?.text">{{ nativeButton.text }}</span>
108
168
  <template v-else>
109
- {{ buttonText }}
169
+ {{ nativeButton.text }}
110
170
  </template>
111
- <span v-if="buttonIcon.iconPosition === 'after'" :class="buttonIcon.iconClass"></span>
171
+ <span v-if="nativeButton?.icon?.show && nativeButton?.icon?.position === 'after'" :class="nativeButton?.icon?.iconClass"></span>
112
172
  </button>
113
173
  <!-- end button -->
174
+
175
+ <!-- begin CmdTooltip -->
176
+ <CmdTooltip v-if="useCustomTooltip" class="box" :class="validationStatus" :relatedId="tooltipId" :toggle-visibility-by-click="true">
177
+ <!-- begin CmdSystemMessage -->
178
+ <CmdSystemMessage
179
+ v-if="getValidationMessage"
180
+ :message="getValidationMessage"
181
+ :validation-status="validationStatus"
182
+ :iconClose="{show: false}"
183
+ />
184
+ <!-- end CmdSystemMessage -->
185
+
186
+ <template v-if="showRequirements && (validationStatus === '' || validationStatus === 'error')">
187
+ <!-- begin list of requirements -->
188
+ <h6>
189
+ {{ getMessage("cmdformelement.headline.requirements_for_input") }}<br/>
190
+ "{{ labelText }}"
191
+ </h6>
192
+ <dl class="list-of-requirements">
193
+ <template v-for="(requirement, index) in inputRequirements" :key="index">
194
+ <dt aria-live="assertive" :class="requirement.valid(modelValue, $attrs) ? 'success' : 'error'">{{ requirement.message }}:</dt>
195
+ <dd :class="requirement.valid(modelValue, $attrs) ? 'success' : 'error'">
196
+ <span aria-live="assertive" :class="requirement.valid(modelValue, $attrs) ? 'icon-check-circle' : 'icon-error-circle'"
197
+ :title="requirement.valid(modelValue, $attrs) ? 'success' : 'error'"></span>
198
+ </dd>
199
+ </template>
200
+ </dl>
201
+ <!-- end list of requirements -->
202
+
203
+ <!-- begin helplink -->
204
+ <hr v-if="helplink?.show"/>
205
+ <a v-if="helplink?.show && helplink?.url" :href="helplink.url" :target="helplink.target" @click.prevent>
206
+ <span v-if="helplink.icon?.iconClass" :class="helplink.icon?.iconClass" :title="helplink.icon?.tooltip"></span>
207
+ <span v-if="helplink.text">{{ helplink.text }}</span>
208
+ </a>
209
+ <!-- end helplink -->
210
+ </template>
211
+ </CmdTooltip>
212
+ <!-- end CmdTooltip -->
114
213
  </template>
115
214
 
116
215
  <script>
216
+ // import mixins
217
+ import I18n from "../mixins/I18n"
218
+ import DefaultMessageProperties from "../mixins/CmdBox/DefaultMessageProperties"
219
+ import FieldValidation from "../mixins/FieldValidation.js"
220
+ import Tooltip from "../mixins/Tooltip.js"
221
+
222
+ // import components
223
+ import CmdSystemMessage from "./CmdSystemMessage"
117
224
  import CmdTooltip from "./CmdTooltip"
118
225
 
119
226
  export default {
120
227
  inheritAttrs: false,
121
228
  name: "FormElement",
122
229
  components: {
230
+ CmdSystemMessage,
123
231
  CmdTooltip
124
232
  },
233
+ mixins: [
234
+ I18n,
235
+ DefaultMessageProperties,
236
+ FieldValidation,
237
+ Tooltip
238
+ ],
125
239
  data() {
126
240
  return {
127
- tooltip: false
241
+ errorOccurred: 0
128
242
  }
129
243
  },
130
244
  props: {
131
245
  /**
132
- * set value for v-model
246
+ * set value for v-model (must be names modelValue in vue3)
133
247
  */
134
- value: {
248
+ modelValue: {
135
249
  type: [String, Boolean, Array, Number],
136
250
  default: ""
137
251
  },
138
252
  /**
139
253
  * set type of native form-element
140
254
  *
141
- * values: input, select, textarea, button
255
+ * @allowedValues: input, select, textarea, button
142
256
  */
143
257
  element: {
144
258
  type: String,
@@ -155,9 +269,9 @@ export default {
155
269
  *
156
270
  * label may not be removed, because it is required for accessibility
157
271
  */
158
- hideLabel: {
272
+ showLabel: {
159
273
  type: Boolean,
160
- default: false
274
+ default: true
161
275
  },
162
276
  /**
163
277
  * text for label
@@ -166,6 +280,52 @@ export default {
166
280
  type: String,
167
281
  required: false
168
282
  },
283
+ /**
284
+ * set to activate to use toggle-switch-styling
285
+ *
286
+ * element-prop must be set to "input" and type-attribute must be set to "checkbox" or "radio"
287
+ *
288
+ * @affectsStyling: true
289
+ */
290
+ toggleSwitch: {
291
+ type: Boolean,
292
+ default: false
293
+ },
294
+ /**
295
+ * text for on-label
296
+ *
297
+ * set to activate switch-label (=label is placed on toggle-switch (not behind))
298
+ * toggleSwitch-prop must be set to "true"
299
+ * element-prop must be set to "input" and type-attribute must be set to "checkbox" or "radio"
300
+ */
301
+ onLabel: {
302
+ type: String,
303
+ required: false
304
+ },
305
+ /**
306
+ * text for off-label
307
+ *
308
+ * set to activate switch-label (=label is placed on toggle-switch (not behind))
309
+ * toggleSwitch-prop must be set to "true"
310
+ * element-prop must be set to "input" and type-attribute must be set to "checkbox" or "radio"
311
+ */
312
+ offLabel: {
313
+ type: String,
314
+ required: false
315
+ },
316
+ /**
317
+ * on/off-, yes/no-color-styling
318
+ *
319
+ * set to true, if checkbox/radio-buttons should have green/checked and red/unchecked color-coding
320
+ * toggleSwitch-prop must be set to "true"
321
+ * element-prop must be set to "input" and type-attribute must be set to "checkbox" or "radio"
322
+ *
323
+ * @affectsStyling: true
324
+ */
325
+ colored: {
326
+ type: Boolean,
327
+ required: false
328
+ },
169
329
  /**
170
330
  * allow checkbox/radio-buttons to get value from outside
171
331
  */
@@ -175,6 +335,8 @@ export default {
175
335
  },
176
336
  /**
177
337
  * for replacing native checkboxes/radio-buttons by custom ones (based on frontend-framework)
338
+ *
339
+ * @affectsStyling: true
178
340
  */
179
341
  replaceInputType: {
180
342
  type: Boolean,
@@ -213,19 +375,20 @@ export default {
213
375
  required: false
214
376
  },
215
377
  /**
216
- * text for native button
217
- */
218
- buttonText: {
219
- type: String,
220
- required: false
221
- },
222
- /**
223
- * set icon for native button
378
+ * native button
224
379
  */
225
- buttonIcon: {
380
+ nativeButton: {
226
381
  type: Object,
227
382
  default() {
228
- return {}
383
+ return {
384
+ text: "",
385
+ icon: {
386
+ show: true,
387
+ iconClass: "",
388
+ position: "left",
389
+ tooltip: ""
390
+ }
391
+ }
229
392
  }
230
393
  },
231
394
  /**
@@ -240,7 +403,7 @@ export default {
240
403
  *
241
404
  * element-property must be 'input' and type-property may not be checkbox or radio
242
405
  */
243
- innerIconClass: {
406
+ fieldIconClass: {
244
407
  type: String,
245
408
  required: false
246
409
  },
@@ -249,51 +412,174 @@ export default {
249
412
  *
250
413
  * type-property may not be checkbox or radio
251
414
  */
252
- displayLabelInline: {
415
+ displayLabelInline: {
253
416
  type: Boolean,
254
417
  required: false
255
418
  },
256
419
  /**
257
420
  * set status for label and form-element
258
421
  *
259
- * values: error (red-styling), success (green-styling)
422
+ * @allowedValues: error, success
423
+ *
424
+ * @affectsStyling: true
260
425
  */
261
426
  status: {
262
427
  type: String,
263
428
  required: false
429
+ },
430
+ /**
431
+ * toggle display of number of used and allowed characters for textarea
432
+ *
433
+ * type-property must be set to textarea
434
+ */
435
+ showCharactersTextarea: {
436
+ type: Boolean,
437
+ default: true
438
+ },
439
+ /**
440
+ * toggle visibility of search-button (next to search-field)
441
+ */
442
+ showSearchButton: {
443
+ type: Boolean,
444
+ default: true
445
+ },
446
+ /**
447
+ * icon to delete search term
448
+ *
449
+ * element-property must me set to 'input'
450
+ * type-property must be set to 'search'
451
+ *
452
+ */
453
+ iconDelete: {
454
+ type: Object,
455
+ default() {
456
+ return {
457
+ show: true,
458
+ iconClass: "icon-cancel-circle",
459
+ tooltip: "Delete term"
460
+ }
461
+ }
462
+ },
463
+ /**
464
+ * icon to search term
465
+ *
466
+ * element-property must me set to 'input'
467
+ * type-property must be set to 'search'
468
+ *
469
+ */
470
+ iconSearch: {
471
+ type: Object,
472
+ default() {
473
+ return {
474
+ show: true,
475
+ iconClass: "icon-search",
476
+ tooltip: "Search"
477
+ }
478
+ }
264
479
  }
265
480
  },
266
481
  computed: {
482
+ buttonAttrs() {
483
+ // copy all native attributes
484
+ const allAttrs = {...this.$attrs}
485
+
486
+ // check if specific tooltip for icon is set (and add as title-attribute)
487
+ if (this.nativeButton.icon?.tooltip) {
488
+ allAttrs.title = this.nativeButton.icon?.tooltip
489
+ }
490
+
491
+ return allAttrs
492
+ },
493
+ tooltipHeadline() {
494
+ return {
495
+ text: this.labelText,
496
+ level: "5"
497
+ }
498
+ },
267
499
  isChecked() {
268
- if (typeof this.value === "boolean") {
269
- return this.value
500
+ if (typeof this.modelValue === "boolean") {
501
+ return this.modelValue
270
502
  }
271
- if (typeof this.value === "string") {
272
- return this.value === this.inputValue
503
+ if (typeof this.modelValue === "string") {
504
+ return this.modelValue === this.inputValue
273
505
  }
274
- if (typeof this.value === "number") {
275
- return this.value === this.inputValue
506
+ if (typeof this.modelValue === "number") {
507
+ return this.modelValue === this.inputValue
276
508
  }
277
- if (this.value !== undefined) {
278
- return this.value.includes(this.inputValue)
509
+ if (this.modelValue !== undefined) {
510
+ return this.modelValue.includes(this.inputValue)
279
511
  }
280
512
  return false
513
+ },
514
+ charactersTextarea() {
515
+ return "Characters: " + this.modelValue.length + "/" + this.getMaxLength()
516
+ },
517
+ validationTooltip() {
518
+ if (!this.useCustomTooltip) {
519
+ return this.getValidationMessage
520
+ }
521
+
522
+ // set default-tooltip if customTooltip is not set
523
+ if (this.validationStatus === 'error') {
524
+ return "An error occurred!"
525
+ } else if (this.validationStatus === 'success') {
526
+ return "This information is filled correctly!"
527
+ } else if (this.capsLockActivated) {
528
+ return "Attention: Caps lock is activated!"
529
+ }
530
+ return "Open field requirements!"
281
531
  }
282
532
  },
283
533
  methods: {
284
- onChange(e) {
285
- if (typeof this.value === "boolean") {
286
- this.$emit("update:value", e.target.checked)
287
- } else if (typeof this.value === "string") {
288
- this.$emit("update:value", e.target.value)
289
- } else if (this.value !== undefined) {
290
- let values = [...this.value]
291
- if (e.target.checked) {
292
- values.push(e.target.value)
534
+ getDomElement() {
535
+ return this.$refs.label
536
+ },
537
+ getMaxLength() {
538
+ return this.$attrs.maxlength > 0 ? this.$attrs.maxlength : 5000
539
+ },
540
+ onBlur(event) {
541
+ // check if surrounding form with data-use-validation exists
542
+ const useValidation = event.target.closest("form")?.dataset.useValidation === "true"
543
+
544
+ if (useValidation) {
545
+ this.tooltip = false
546
+ this.validationStatus = ""
547
+
548
+ // if input is filled, set status to success (expect for checkboxes and radiobuttons)
549
+ if (!["checkbox", "radio"].includes(this.$attrs.type) && this.modelValue) {
550
+ this.validationStatus = "success"
551
+ }
552
+
553
+ if (typeof event.target.checkValidity === "function" && !event.target.checkValidity()) {
554
+ this.validationStatus = "error"
555
+ } else {
556
+ if (this.customRequirements) {
557
+ // check if customRequirement returns invalid result
558
+ const invalidCustomRequirement = this.customRequirements.some(requirement => {
559
+ return !requirement.valid(this.modelValue)
560
+ })
561
+
562
+ // set validation-status if invalidCustomRequirement returns at least one invalid entry
563
+ if (invalidCustomRequirement) {
564
+ this.validationStatus = "error"
565
+ }
566
+ }
567
+ }
568
+ }
569
+ },
570
+ onChange(event) {
571
+ if (typeof this.modelValue === "boolean") {
572
+ this.$emit("update:modelValue", event.target.checked)
573
+ } else if (typeof this.modelValue === "string") {
574
+ this.$emit("update:modelValue", event.target.value)
575
+ } else if (this.modelValue !== undefined) {
576
+ let values = [...this.modelValue]
577
+ if (event.target.checked) {
578
+ values.push(event.target.value)
293
579
  } else {
294
- values = values.filter(value => value !== e.target.value)
580
+ values = values.filter(value => value !== event.target.value)
295
581
  }
296
- this.$emit("update:value", values)
582
+ this.$emit("update:modelValue", values)
297
583
  }
298
584
  },
299
585
  datalistFocus() {
@@ -302,9 +588,168 @@ export default {
302
588
  this.$refs.label.focus()
303
589
  }
304
590
  },
305
- onInput(e) {
306
- this.$emit('update:value', e.target.value)
591
+ onInput(event) {
592
+ this.$emit('update:modelValue', event.target.value)
593
+ },
594
+ showPassword() {
595
+ // get password-field
596
+ const passwordField = this.$refs.input
597
+
598
+ // get value of password field (to save it temporary)
599
+ const password = passwordField.value
600
+
601
+ // toggle input-type to make password visible
602
+ passwordField.nextElementSibling.classList.replace("icon-visible", "icon-not-visible")
603
+ passwordField.setAttribute("type", "text")
604
+
605
+ // assign saved password back to field
606
+ passwordField.setAttribute("value", password)
607
+ },
608
+ hidePassword() {
609
+ this.$refs.input.nextElementSibling.classList.replace("icon-not-visible", "icon-visible")
610
+ this.$refs.input.setAttribute("type", "password")
611
+ }
612
+ },
613
+ watch: {
614
+ status: {
615
+ handler() {
616
+ this.validationStatus = this.status
617
+ },
618
+ immediate: true
307
619
  }
308
620
  }
309
621
  }
310
622
  </script>
623
+
624
+ <style lang="scss">
625
+ .cmd-form-element {
626
+ input + .place-inside[class*="icon"] {
627
+ left: auto;
628
+ right: .5rem
629
+ }
630
+
631
+ &.has-state, & + .cmd-tooltip {
632
+ &.error {
633
+ --status-color: var(--error-color);
634
+ }
635
+
636
+ &.warning {
637
+ --status-color: var(--warning-color);
638
+ }
639
+
640
+ &.success {
641
+ --status-color: var(--success-color);
642
+ }
643
+
644
+ &.info {
645
+ --status-color: var(--info-color);
646
+ }
647
+
648
+ ::placeholder {
649
+ color: var(--status-color);
650
+ }
651
+
652
+ > span {
653
+ color: var(--status-color);
654
+
655
+ &[class*="icon-"].place-inside {
656
+ color: var(--status-color);
657
+ }
658
+ }
659
+ }
660
+
661
+ & + .cmd-tooltip {
662
+ border-color: var(--status-color);
663
+ }
664
+
665
+ &.inline {
666
+ & > span {
667
+ & > a {
668
+ margin-left: calc(var(--default-margin) / 2);
669
+ }
670
+ }
671
+ }
672
+
673
+ .search-field-wrapper {
674
+ margin: 0;
675
+ }
676
+
677
+ .place-inside {
678
+ + .search-field-wrapper {
679
+ a {
680
+ position: absolute;
681
+ top: 50%;
682
+ right: 1rem;
683
+ transform: translateY(-50%);
684
+ z-index: 100;
685
+
686
+ & + input {
687
+ padding-right: calc(var(--default-padding) * 3);
688
+ }
689
+ }
690
+
691
+ input {
692
+ padding-left: calc(var(--default-padding) * 3);
693
+ }
694
+ }
695
+ }
696
+
697
+ /* begin toggle-switch */
698
+ /* no cmd-prefix-styling (class based on frontend-framework */
699
+ &.toggle-switch {
700
+ &.switch-label {
701
+ input {
702
+ & + .label {
703
+ padding-right: calc(var(--default-padding) / 3 * 2);
704
+
705
+ &::before {
706
+ top: 0.2rem;
707
+ }
708
+
709
+ & + .label {
710
+ padding-left: calc(var(--default-padding) / 3 * 2);
711
+
712
+ &::before {
713
+ top: 0.2rem;
714
+ }
715
+ }
716
+ }
717
+ }
718
+
719
+ &.colored {
720
+ &.off {
721
+ border-color: var(--error-color);
722
+
723
+ span {
724
+ &.label {
725
+ color: var(--error-color);
726
+
727
+ &::before {
728
+ border-color: var(--error-color);
729
+ background-color: var(--pure-white);
730
+ }
731
+ }
732
+ }
733
+ }
734
+
735
+ &.on {
736
+ border-color: var(--success-color);
737
+
738
+ span {
739
+ &.label {
740
+ color: var(--success-color);
741
+
742
+ &::before {
743
+ border-color: var(--success-color);
744
+ background-color: var(--success-color);
745
+ }
746
+ }
747
+ }
748
+ }
749
+ }
750
+ }
751
+ }
752
+
753
+ /* end toggle-switch ------------------------------------------------------------------------------------------ */
754
+ }
755
+ </style>