comand-component-library 3.1.45 → 3.1.48

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.
Files changed (233) 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 -41
  4. package/src/App.vue +373 -135
  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-filter-options.json +14 -0
  16. package/src/assets/data/fake-select-options-with-icons.json +6 -12
  17. package/src/assets/data/fake-select-options.json +3 -3
  18. package/src/assets/data/list-of-links-section-anchors.json +23 -0
  19. package/src/assets/data/list-of-links-top-header-navigation.json +20 -0
  20. package/src/assets/data/list-of-links.json +42 -0
  21. package/src/assets/data/main-navigation.json +48 -0
  22. package/src/assets/data/multistep-form-progress-bar.json +33 -0
  23. package/src/assets/data/select-options.json +4 -0
  24. package/src/assets/data/{share-buttons.json → share-buttons-page-by-json.json} +8 -8
  25. package/src/assets/data/share-buttons-page-by-property.json +30 -0
  26. package/src/assets/data/switch-language.json +20 -0
  27. package/src/assets/data/table-large.json +1 -1
  28. package/src/assets/data/table-small.json +1 -1
  29. package/src/assets/styles/global-styles.scss +43 -13
  30. package/src/assets/styles/transitions.scss +21 -1
  31. package/src/components/CmdAccordion.vue +43 -42
  32. package/src/components/CmdAddressData.vue +124 -56
  33. package/src/components/CmdBackToTopButton.vue +3 -3
  34. package/src/components/CmdBankAccountData.vue +104 -0
  35. package/src/components/CmdBox.vue +253 -56
  36. package/src/components/CmdBoxSiteSearch.vue +138 -39
  37. package/src/components/CmdBoxWrapper.vue +206 -0
  38. package/src/components/CmdBreadcrumbs.vue +29 -13
  39. package/src/components/CmdCompanyLogo.vue +6 -4
  40. package/src/components/CmdCookieDisclaimer.vue +99 -75
  41. package/src/components/CmdCopyrightInformation.vue +1 -1
  42. package/src/components/CmdCustomHeadline.vue +93 -0
  43. package/src/components/CmdFakeSelect.vue +285 -60
  44. package/src/components/CmdFancyBox.vue +47 -33
  45. package/src/components/CmdForm.vue +107 -0
  46. package/src/components/CmdFormElement.vue +515 -81
  47. package/src/components/CmdFormFilters.vue +25 -11
  48. package/src/components/CmdGoogleMaps.vue +9 -3
  49. package/src/components/CmdImageGallery.vue +28 -5
  50. package/src/components/CmdImageZoom.vue +9 -1
  51. package/src/components/CmdListOfLinks.vue +169 -0
  52. package/src/components/CmdLoginForm.vue +143 -63
  53. package/src/components/CmdMainNavigation.vue +140 -42
  54. package/src/components/CmdMultipleSwitch.vue +33 -2
  55. package/src/components/CmdMultistepFormProgressBar.vue +60 -10
  56. package/src/components/CmdOpeningHours.vue +36 -10
  57. package/src/components/CmdPager.vue +7 -5
  58. package/src/components/CmdProgressBar.vue +20 -3
  59. package/src/components/CmdShareButtons.vue +64 -9
  60. package/src/components/CmdSiteHeader.vue +27 -14
  61. package/src/components/CmdSlideButton.vue +5 -2
  62. package/src/components/CmdSlideshow.vue +23 -7
  63. package/src/components/CmdSwitchButton.vue +10 -3
  64. package/src/components/CmdSwitchLanguage.vue +18 -10
  65. package/src/components/CmdSystemMessage.vue +30 -17
  66. package/src/components/CmdTable.vue +15 -7
  67. package/src/components/CmdTabs.vue +43 -3
  68. package/src/components/CmdThumbnailScroller.vue +22 -6
  69. package/src/components/CmdTooltip.vue +184 -11
  70. package/src/components/CmdUploadForm.vue +198 -92
  71. package/src/components/CmdWidthLimitationWrapper.vue +9 -6
  72. package/src/composables/event.js +8 -0
  73. package/src/composables/scrollspy.js +52 -0
  74. package/src/directives/focus.js +19 -0
  75. package/src/directives/telephone.js +1 -1
  76. package/src/documentation/commonProps.js +6 -0
  77. package/src/documentation/components/ComponentCode.vue +50 -0
  78. package/src/documentation/components/ComponentProperties.vue +237 -0
  79. package/src/documentation/components/ExampleSectionWrapper.vue +46 -0
  80. package/src/documentation/components/ViewCodeData.vue +113 -0
  81. package/src/documentation/data/CmdAccordionHelp.js +22 -0
  82. package/src/documentation/data/CmdAddressDataHelp.js +17 -0
  83. package/src/documentation/data/CmdBackToTopButtonHelp.js +3 -0
  84. package/src/documentation/data/CmdBankAccountDataHelp.js +8 -0
  85. package/src/documentation/data/CmdBoxHelp.js +45 -0
  86. package/src/documentation/data/CmdBoxSiteSearchHelp.js +11 -0
  87. package/src/documentation/data/CmdBreadcrumbsHelp.js +6 -0
  88. package/src/documentation/data/CmdCompanyLogoHelp.js +8 -0
  89. package/src/documentation/data/CmdCookieDisclaimerHelp.js +9 -0
  90. package/src/documentation/data/CmdCopyrightInformation.js +2 -0
  91. package/src/documentation/data/CmdCustomHeadlineHelp.js +8 -0
  92. package/src/documentation/data/CmdFakeSelectHelp.js +60 -0
  93. package/src/documentation/data/CmdFancyBoxHelp.js +7 -0
  94. package/src/documentation/data/CmdFooterNavigationHelp.js +5 -0
  95. package/src/documentation/data/CmdFormElementHelp.js +189 -0
  96. package/src/documentation/data/CmdFormFiltersHelp.js +6 -0
  97. package/src/documentation/data/CmdFormHelp.js +10 -0
  98. package/src/documentation/data/CmdGoogleMapsHelp.js +5 -0
  99. package/src/documentation/data/CmdImageGalleryHelp.js +5 -0
  100. package/src/documentation/data/CmdImageZoomHelp.js +6 -0
  101. package/src/documentation/data/CmdListOfLinksHelp.js +24 -0
  102. package/src/documentation/data/CmdLoginFormHelp.js +6 -0
  103. package/src/documentation/data/CmdMainNavigationHelp.js +7 -0
  104. package/src/documentation/data/CmdMultistepFormProgressBarHelp.js +6 -0
  105. package/src/documentation/data/CmdOpeningHoursHelp.js +10 -0
  106. package/src/documentation/data/CmdPagerHelp.js +7 -0
  107. package/src/documentation/data/CmdProgressBarHelp.js +13 -0
  108. package/src/documentation/data/CmdShareButtonsHelp.js +13 -0
  109. package/src/documentation/data/CmdSiteHeaderHelp.js +21 -0
  110. package/src/documentation/data/CmdSlideButtonHelp.js +10 -0
  111. package/src/documentation/data/CmdSlideshowHelp.js +7 -0
  112. package/src/documentation/data/CmdSwitchLanguageHelp.js +6 -0
  113. package/src/documentation/data/CmdSystemMessageHelp.js +32 -0
  114. package/src/documentation/data/CmdTableHelp.js +14 -0
  115. package/src/documentation/data/CmdTabsHelp.js +10 -0
  116. package/src/documentation/data/CmdThumbnailScrollerHelp.js +5 -0
  117. package/src/documentation/data/CmdTooltipHelp.js +13 -0
  118. package/src/documentation/data/CmdUploadFormHelp.js +17 -0
  119. package/src/documentation/data/CmdWidthLimitationWrapperHelp.js +7 -0
  120. package/src/documentation/data/componentsDescription.json +158 -0
  121. package/src/documentation/generated/CmdAccordionPropertyDescriptions.json +57 -0
  122. package/src/documentation/generated/CmdAddressDataPropertyDescriptions.json +32 -0
  123. package/src/documentation/generated/CmdBackToTopButtonPropertyDescriptions.json +12 -0
  124. package/src/documentation/generated/CmdBankAccountDataPropertyDescriptions.json +34 -0
  125. package/src/documentation/generated/CmdBoxPropertyDescriptions.json +91 -0
  126. package/src/documentation/generated/CmdBoxSiteSearchPropertyDescriptions.json +41 -0
  127. package/src/documentation/generated/CmdBoxWrapperPropertyDescriptions.json +47 -0
  128. package/src/documentation/generated/CmdBreadcrumbsPropertyDescriptions.json +17 -0
  129. package/src/documentation/generated/CmdCompanyLogoPropertyDescriptions.json +27 -0
  130. package/src/documentation/generated/CmdCookieDisclaimerPropertyDescriptions.json +22 -0
  131. package/src/documentation/generated/CmdCustomHeadlinePropertyDescriptions.json +22 -0
  132. package/src/documentation/generated/CmdFakeSelectPropertyDescriptions.json +79 -0
  133. package/src/documentation/generated/CmdFancyBoxPropertyDescriptions.json +62 -0
  134. package/src/documentation/generated/CmdFooterNavigationPropertyDescriptions.json +17 -0
  135. package/src/documentation/generated/CmdFormElementPropertyDescriptions.json +178 -0
  136. package/src/documentation/generated/CmdFormFiltersPropertyDescriptions.json +32 -0
  137. package/src/documentation/generated/CmdFormPropertyDescriptions.json +40 -0
  138. package/src/documentation/generated/CmdGoogleMapsPropertyDescriptions.json +7 -0
  139. package/src/documentation/generated/CmdImageGalleryPropertyDescriptions.json +22 -0
  140. package/src/documentation/generated/CmdImageZoomPropertyDescriptions.json +12 -0
  141. package/src/documentation/generated/CmdListOfLinksPropertyDescriptions.json +60 -0
  142. package/src/documentation/generated/CmdLoginFormPropertyDescriptions.json +90 -0
  143. package/src/documentation/generated/CmdMainNavigationPropertyDescriptions.json +62 -0
  144. package/src/documentation/generated/CmdMultipleSwitchPropertyDescriptions.json +52 -0
  145. package/src/documentation/generated/CmdMultistepFormProgressBarPropertyDescriptions.json +17 -0
  146. package/src/documentation/generated/CmdOpeningHoursPropertyDescriptions.json +42 -0
  147. package/src/documentation/generated/CmdPagerPropertyDescriptions.json +37 -0
  148. package/src/documentation/generated/CmdProgressBarPropertyDescriptions.json +32 -0
  149. package/src/documentation/generated/CmdShareButtonsPropertyDescriptions.json +34 -0
  150. package/src/documentation/generated/CmdSiteHeaderPropertyDescriptions.json +27 -0
  151. package/src/documentation/generated/CmdSlideButtonPropertyDescriptions.json +25 -0
  152. package/src/documentation/generated/CmdSlideshowPropertyDescriptions.json +42 -0
  153. package/src/documentation/generated/CmdSwitchButtonPropertyDescriptions.json +79 -0
  154. package/src/documentation/generated/CmdSwitchLanguagePropertyDescriptions.json +7 -0
  155. package/src/documentation/generated/CmdSystemMessagePropertyDescriptions.json +40 -0
  156. package/src/documentation/generated/CmdTablePropertyDescriptions.json +62 -0
  157. package/src/documentation/generated/CmdTabsPropertyDescriptions.json +27 -0
  158. package/src/documentation/generated/CmdThumbnailScrollerPropertyDescriptions.json +32 -0
  159. package/src/documentation/generated/CmdTooltipPropertyDescriptions.json +17 -0
  160. package/src/documentation/generated/CmdUploadFormPropertyDescriptions.json +90 -0
  161. package/src/documentation/generated/CmdWidthLimitationWrapperPropertyDescriptions.json +41 -0
  162. package/src/documentation/generated/frameworkIcons.json +730 -0
  163. package/src/documentation/generated/logosIcons.json +110 -0
  164. package/src/documentation/tabs.js +46 -0
  165. package/src/documentation/views/ContainerPage.vue +237 -0
  166. package/src/documentation/views/HelpHome.vue +13 -0
  167. package/src/documentation/views/IconFont.vue +80 -0
  168. package/src/documentation/views/components/CmdAccordionHelp.vue +78 -0
  169. package/src/documentation/views/components/CmdAddressDataHelp.vue +65 -0
  170. package/src/documentation/views/components/CmdBackToTopButtonHelp.vue +62 -0
  171. package/src/documentation/views/components/CmdBankAccountDataHelp.vue +88 -0
  172. package/src/documentation/views/components/CmdBoxHelp.vue +137 -0
  173. package/src/documentation/views/components/CmdBoxSiteSearchHelp.vue +60 -0
  174. package/src/documentation/views/components/CmdBoxWrapperHelp.vue +111 -0
  175. package/src/documentation/views/components/CmdBreadcrumbsHelp.vue +51 -0
  176. package/src/documentation/views/components/CmdCompanyLogoHelp.vue +48 -0
  177. package/src/documentation/views/components/CmdCookieDisclaimerHelp.vue +105 -0
  178. package/src/documentation/views/components/CmdCustomHeadlineHelp.vue +53 -0
  179. package/src/documentation/views/components/CmdFakeSelectHelp.vue +175 -0
  180. package/src/documentation/views/components/CmdFancyBoxHelp.vue +79 -0
  181. package/src/documentation/views/components/CmdFormElementHelp.vue +412 -0
  182. package/src/documentation/views/components/CmdFormFiltersHelp.vue +69 -0
  183. package/src/documentation/views/components/CmdFormHelp.vue +41 -0
  184. package/src/documentation/views/components/CmdGoogleMapsHelp.vue +55 -0
  185. package/src/documentation/views/components/CmdImageGalleryHelp.vue +46 -0
  186. package/src/documentation/views/components/CmdImageZoomHelp.vue +34 -0
  187. package/src/documentation/views/components/CmdListOfLinksHelp.vue +64 -0
  188. package/src/documentation/views/components/CmdLoginFormHelp.vue +117 -0
  189. package/src/documentation/views/components/CmdMainNavigationHelp.vue +94 -0
  190. package/src/documentation/views/components/CmdMultistepFormProgressBarHelp.vue +49 -0
  191. package/src/documentation/views/components/CmdOpeningHoursHelp.vue +49 -0
  192. package/src/documentation/views/components/CmdPagerHelp.vue +57 -0
  193. package/src/documentation/views/components/CmdProgressBarHelp.vue +47 -0
  194. package/src/documentation/views/components/CmdShareButtonsHelp.vue +65 -0
  195. package/src/documentation/views/components/CmdSiteHeaderHelp.vue +72 -0
  196. package/src/documentation/views/components/CmdSlideButtonHelp.vue +90 -0
  197. package/src/documentation/views/components/CmdSlideshowHelp.vue +60 -0
  198. package/src/documentation/views/components/CmdSwitchLanguageHelp.vue +64 -0
  199. package/src/documentation/views/components/CmdSystemMessageHelp.vue +86 -0
  200. package/src/documentation/views/components/CmdTableHelp.vue +84 -0
  201. package/src/documentation/views/components/CmdTabsHelp.vue +52 -0
  202. package/src/documentation/views/components/CmdThumbnailScrollerHelp.vue +50 -0
  203. package/src/documentation/views/components/CmdTooltipHelp.vue +59 -0
  204. package/src/documentation/views/components/CmdUploadFormHelp.vue +59 -0
  205. package/src/documentation/views/components/CmdWidthLimitationWrapperHelp.vue +46 -0
  206. package/src/index.js +7 -3
  207. package/src/main.js +25 -15
  208. package/src/mixins/CmdAddressData/DefaultMessageProperties.js +17 -0
  209. package/src/mixins/CmdBox/DefaultMessageProperties.js +10 -0
  210. package/src/mixins/CmdFakeSelect/DefaultMessageProperties.js +9 -0
  211. package/src/mixins/CmdFormElement/DefaultMessageProperties.js +9 -0
  212. package/src/mixins/CmdImageGallery/DefaultMessageProperties.js +9 -0
  213. package/src/mixins/CmdSiteSearch/DefaultMessageProperties.js +14 -0
  214. package/src/mixins/CmdUploadForm/DefaultMessageProperties.js +5 -1
  215. package/src/mixins/FieldValidation.js +220 -0
  216. package/src/mixins/GlobalDefaultMessageProperties.js +15 -0
  217. package/src/mixins/Tooltip.js +26 -0
  218. package/src/router/index.js +67 -0
  219. package/src/utilities.js +3 -6
  220. package/src/utils/common.js +6 -0
  221. package/src/utils/dom.js +8 -0
  222. package/src/utils/globalSequence.js +13 -0
  223. package/src/utils/string.js +8 -0
  224. package/src/assets/data/address.json +0 -13
  225. package/src/assets/data/footer-navigation.json +0 -38
  226. package/src/assets/data/languages.json +0 -31
  227. package/src/assets/data/multisteps.json +0 -27
  228. package/src/assets/data/navigation.json +0 -47
  229. package/src/assets/data/pager.json +0 -11
  230. package/src/assets/data/top-header-navigation.json +0 -27
  231. package/src/components/CmdFooterNavigation.vue +0 -71
  232. package/src/components/CmdMainHeadline.vue +0 -75
  233. package/src/components/CmdTopHeaderNavigation.vue +0 -88
@@ -1,39 +1,81 @@
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 asterisk) -->
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 asterisk) -->
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
- <!-- begin inner-icon -->
15
- <span v-if="$attrs.type !== 'checkbox' && $attrs.type !== 'radio' && innerIconClass" :class="['place-inside', status, innerIconClass]"></span>
16
- <!-- end inner-icon -->
38
+ <!-- begin icon -->
39
+ <span
40
+ v-if="
41
+ $attrs.type !== 'checkbox' &&
42
+ $attrs.type !== 'radio' &&
43
+ fieldIconClass
44
+ "
45
+ :class="['place-inside', fieldIconClass]"
46
+ ></span>
47
+ <!-- end icon -->
17
48
 
18
49
  <!-- begin inputfield -->
19
50
  <template
20
51
  v-if="element === 'input' && $attrs.type !== 'checkbox' && $attrs.type !== 'radio' && $attrs.type !== 'search'">
21
52
  <input v-bind="$attrs"
22
- :id="id" :class="htmlClass"
53
+ :id="id"
54
+ :class="htmlClass"
23
55
  @focus="tooltip = true"
24
- @blur="tooltip = false"
56
+ @blur="onBlur"
25
57
  @input="onInput"
26
58
  @mouseover="datalistFocus"
27
- @change="$emit('change', $event)"
59
+ @keyup="checkForCapsLock"
28
60
  :autocomplete="datalist ? 'off' : 'on'"
29
61
  :list="datalist ? datalist.id : false"
30
- :value="value"
62
+ :value="modelValue"
63
+ :maxlength="$attrs.maxlength > 0 ? $attrs.maxlength : 255"
64
+ ref="input"
31
65
  />
32
66
  </template>
33
67
  <!-- end inputfield -->
34
68
 
35
69
  <!-- begin show-password-icon -->
36
- <a v-if="$attrs.type === 'password'" href="#" @click.prevent="showPassword" class="place-inside icon-visible" title="Toggle password visibility"></a>
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>
37
79
  <!-- end show-password-icon -->
38
80
 
39
81
  <!-- begin datalist -->
@@ -48,18 +90,32 @@
48
90
  <template v-else-if="element === 'input' && ($attrs.type === 'checkbox' || $attrs.type === 'radio')">
49
91
  <input v-bind="$attrs"
50
92
  @change="onChange"
93
+ @blur="onBlur"
51
94
  :checked="isChecked"
95
+ :role="$attrs.type"
96
+ :aria-checked="isChecked"
52
97
  :value="inputValue"
53
- :class="[htmlClass, status, { 'replace-input-type': replaceInputType }]"
98
+ :class="[htmlClass, validationStatus, { 'replace-input-type': replaceInputType, 'toggle-switch': toggleSwitch }]"
54
99
  :id="id"
55
- :aria-invalid="status === 'error'"
100
+ :aria-invalid="validationStatus === 'error'"
56
101
  :aria-describedby="`status-message-${id}`"
57
102
  />
58
- <span v-if="labelText">
59
- <span>{{ labelText }}</span>
60
- <sup v-if="$attrs.required">*</sup>
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>
61
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>
62
117
  <slot v-else></slot>
118
+ <!-- end labels for toggle-switch -->
63
119
  </template>
64
120
  <!-- end checkbox and radiobutton -->
65
121
 
@@ -67,10 +123,10 @@
67
123
  <select v-if="element === 'select'"
68
124
  v-bind="$attrs"
69
125
  :id="id"
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,65 +135,124 @@
79
135
  <textarea v-if="element === 'textarea'"
80
136
  v-bind="$attrs"
81
137
  :id="id"
82
- :value="value"
138
+ :value="modelValue"
139
+ :maxlength="getMaxLength"
83
140
  @input="onInput"
84
141
  @focus="tooltip = true"
85
- @blur="tooltip = false">
142
+ @blur="onBlur">
86
143
  </textarea>
144
+ <span v-if="element === 'textarea' && showCharactersTextarea">{{ charactersTextarea }}</span>
87
145
  <!-- end textarea -->
88
146
 
89
- <!-- begin tooltip -->
90
- <CmdTooltip v-if="tooltip && tooltipText" :tooltipText="tooltipText"/>
91
- <!-- end tooltip -->
92
-
93
147
  <!-- begin searchfield -->
94
- <span v-else-if="element === 'input' && $attrs.type === 'search'" class="flex-container no-gap">
95
- <input v-bind="$attrs" :id="id" @input="onInput" :value="value"/>
96
- <button class="no-flex" type="button">
97
- <span class="icon-search"></span>
98
- </button>
99
- </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>
100
161
  <!-- end searchfield -->
101
162
  </label>
102
163
 
103
164
  <!-- begin button -->
104
- <button v-else class="button" v-bind="$attrs">
105
- <span v-if="buttonIcon.iconPosition === 'before'" :class="buttonIcon.iconClass"></span>
106
- <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>
107
168
  <template v-else>
108
- {{ buttonText }}
169
+ {{ nativeButton.text }}
109
170
  </template>
110
- <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>
111
172
  </button>
112
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 -->
113
213
  </template>
114
214
 
115
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"
116
224
  import CmdTooltip from "./CmdTooltip"
117
225
 
118
226
  export default {
119
227
  inheritAttrs: false,
120
228
  name: "FormElement",
121
229
  components: {
230
+ CmdSystemMessage,
122
231
  CmdTooltip
123
232
  },
233
+ mixins: [
234
+ I18n,
235
+ DefaultMessageProperties,
236
+ FieldValidation,
237
+ Tooltip
238
+ ],
124
239
  data() {
125
240
  return {
126
- tooltip: false
241
+ errorOccurred: 0
127
242
  }
128
243
  },
129
244
  props: {
130
245
  /**
131
- * set value for v-model
246
+ * set value for v-model (must be names modelValue in vue3)
132
247
  */
133
- value: {
248
+ modelValue: {
134
249
  type: [String, Boolean, Array, Number],
135
250
  default: ""
136
251
  },
137
252
  /**
138
253
  * set type of native form-element
139
254
  *
140
- * values: input, select, textarea, button
255
+ * @allowedValues: input, select, textarea, button
141
256
  */
142
257
  element: {
143
258
  type: String,
@@ -154,9 +269,9 @@ export default {
154
269
  *
155
270
  * label may not be removed, because it is required for accessibility
156
271
  */
157
- hideLabel: {
272
+ showLabel: {
158
273
  type: Boolean,
159
- default: false
274
+ default: true
160
275
  },
161
276
  /**
162
277
  * text for label
@@ -165,6 +280,52 @@ export default {
165
280
  type: String,
166
281
  required: false
167
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
+ },
168
329
  /**
169
330
  * allow checkbox/radio-buttons to get value from outside
170
331
  */
@@ -174,6 +335,8 @@ export default {
174
335
  },
175
336
  /**
176
337
  * for replacing native checkboxes/radio-buttons by custom ones (based on frontend-framework)
338
+ *
339
+ * @affectsStyling: true
177
340
  */
178
341
  replaceInputType: {
179
342
  type: Boolean,
@@ -212,19 +375,20 @@ export default {
212
375
  required: false
213
376
  },
214
377
  /**
215
- * text for native button
216
- */
217
- buttonText: {
218
- type: String,
219
- required: false
220
- },
221
- /**
222
- * set icon for native button
378
+ * native button
223
379
  */
224
- buttonIcon: {
380
+ nativeButton: {
225
381
  type: Object,
226
382
  default() {
227
- return {}
383
+ return {
384
+ text: "",
385
+ icon: {
386
+ show: true,
387
+ iconClass: "",
388
+ position: "left",
389
+ tooltip: ""
390
+ }
391
+ }
228
392
  }
229
393
  },
230
394
  /**
@@ -239,7 +403,7 @@ export default {
239
403
  *
240
404
  * element-property must be 'input' and type-property may not be checkbox or radio
241
405
  */
242
- innerIconClass: {
406
+ fieldIconClass: {
243
407
  type: String,
244
408
  required: false
245
409
  },
@@ -248,51 +412,174 @@ export default {
248
412
  *
249
413
  * type-property may not be checkbox or radio
250
414
  */
251
- displayLabelInline: {
415
+ displayLabelInline: {
252
416
  type: Boolean,
253
417
  required: false
254
418
  },
255
419
  /**
256
420
  * set status for label and form-element
257
421
  *
258
- * values: error (red-styling), success (green-styling)
422
+ * @allowedValues: error, success
423
+ *
424
+ * @affectsStyling: true
259
425
  */
260
426
  status: {
261
427
  type: String,
262
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
+ }
263
479
  }
264
480
  },
265
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
+ },
266
499
  isChecked() {
267
- if (typeof this.value === "boolean") {
268
- return this.value
500
+ if (typeof this.modelValue === "boolean") {
501
+ return this.modelValue
269
502
  }
270
- if (typeof this.value === "string") {
271
- return this.value === this.inputValue
503
+ if (typeof this.modelValue === "string") {
504
+ return this.modelValue === this.inputValue
272
505
  }
273
- if (typeof this.value === "number") {
274
- return this.value === this.inputValue
506
+ if (typeof this.modelValue === "number") {
507
+ return this.modelValue === this.inputValue
275
508
  }
276
- if (this.value !== undefined) {
277
- return this.value.includes(this.inputValue)
509
+ if (this.modelValue !== undefined) {
510
+ return this.modelValue.includes(this.inputValue)
278
511
  }
279
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!"
280
531
  }
281
532
  },
282
533
  methods: {
283
- onChange(e) {
284
- if (typeof this.value === "boolean") {
285
- this.$emit("update:value", e.target.checked)
286
- } else if (typeof this.value === "string") {
287
- this.$emit("update:value", e.target.value)
288
- } else if (this.value !== undefined) {
289
- let values = [...this.value]
290
- if (e.target.checked) {
291
- 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"
292
555
  } else {
293
- values = values.filter(value => value !== e.target.value)
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
+ }
294
567
  }
295
- this.$emit("update:value", values)
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)
579
+ } else {
580
+ values = values.filter(value => value !== event.target.value)
581
+ }
582
+ this.$emit("update:modelValue", values)
296
583
  }
297
584
  },
298
585
  datalistFocus() {
@@ -301,11 +588,34 @@ export default {
301
588
  this.$refs.label.focus()
302
589
  }
303
590
  },
304
- onInput(e) {
305
- this.$emit('update:value', e.target.value)
591
+ onInput(event) {
592
+ this.$emit('update:modelValue', event.target.value)
306
593
  },
307
594
  showPassword() {
308
- alert(this.$el)
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
309
619
  }
310
620
  }
311
621
  }
@@ -317,5 +627,129 @@ export default {
317
627
  left: auto;
318
628
  right: .5rem
319
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 ------------------------------------------------------------------------------------------ */
320
754
  }
321
755
  </style>