@cnamts/synapse 1.0.12 → 1.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{DateFilter-DoCcOfDW.js → DateFilter-_EFzsvvM.js} +1 -1
- package/dist/{NumberFilter-9uR8uo6p.js → NumberFilter-CUxEbKJh.js} +1 -1
- package/dist/{PeriodFilter-CxN5ini7.js → PeriodFilter-D5ueqtKy.js} +1 -1
- package/dist/{SelectFilter-bfxipgvt.js → SelectFilter-BciBNydy.js} +1 -1
- package/dist/{TextFilter-yCnWcmW2.js → TextFilter-DMN_WAQB.js} +1 -1
- package/dist/components/Amelipro/AmeliproAccordion/AmeliproAccordion.d.ts +1 -1
- package/dist/components/Amelipro/AmeliproAccordion/AmeliproAccordionTemplate/AmeliproAccordionTemplate.d.ts +1 -1
- package/dist/components/Amelipro/AmeliproAccordionResult/AmeliproAccordionResult.d.ts +1 -1
- package/dist/components/Amelipro/AmeliproAccordionResult/AmeliproAccordionResultTemplate/AmeliproAccordionResultTemplate.d.ts +1 -1
- package/dist/components/Amelipro/AmeliproAutoCompleteField/AmeliproAutoCompleteField.d.ts +44 -62
- package/dist/components/Amelipro/AmeliproCard/AmeliproCard.d.ts +1 -1
- package/dist/components/Amelipro/AmeliproIcon/AmeliproIcon.d.ts +1 -1
- package/dist/components/Amelipro/AmeliproIconBtn/AmeliproIconBtn.d.ts +5 -5
- package/dist/components/Amelipro/AmeliproMultipleFoldingCard/AmeliproMultipleFoldingCard.d.ts +1 -1
- package/dist/components/Amelipro/AmeliproNumberedCard/AmeliproNumberedCard.d.ts +1 -1
- package/dist/components/Amelipro/AmeliproPostalAddressField/AmeliproPostalAddressCityRow/AmeliproPostalAddressCityRow.d.ts +24 -32
- package/dist/components/Amelipro/AmeliproPostalAddressField/AmeliproPostalAddressField.d.ts +36 -48
- package/dist/components/Amelipro/AmeliproSelect/AmeliproSelect.d.ts +44 -62
- package/dist/components/Amelipro/AmeliproTabs/AmeliproTabs.d.ts +44 -62
- package/dist/components/Amelipro/AmeliproTextArea/AmeliproTextArea.d.ts +0 -4
- package/dist/components/Amelipro/AmeliproTextField/AmeliproTextField.d.ts +12 -16
- package/dist/components/Captcha/Captcha.d.ts +68 -0
- package/dist/components/Captcha/CaptchaAlert.d.ts +13 -0
- package/dist/components/Captcha/CaptchaBase.d.ts +55 -0
- package/dist/components/Captcha/CaptchaBtn.d.ts +12 -0
- package/dist/components/Captcha/CaptchaForm.d.ts +16 -0
- package/dist/components/Captcha/CaptchaImg.d.ts +12 -0
- package/dist/components/Captcha/CaptchaInformation.d.ts +20 -0
- package/dist/components/Captcha/captchaApi.d.ts +41 -0
- package/dist/components/Captcha/icons/volumeUp.d.ts +2 -0
- package/dist/components/Captcha/locales.d.ts +35 -0
- package/dist/components/Captcha/types.d.ts +2 -0
- package/dist/components/ChipList/ChipList.d.ts +2 -2
- package/dist/components/Customs/Selects/SySelect/SySelect.d.ts +2 -2
- package/dist/components/Customs/SyForm/SyForm.d.ts +6 -3
- package/dist/components/Customs/SyTextField/SyTextField.d.ts +13 -17
- package/dist/components/DatePicker/CalendarMode/DatePicker.d.ts +56 -64
- package/dist/components/DatePicker/ComplexDatePicker/ComplexDatePicker.d.ts +47 -64
- package/dist/components/DatePicker/DateTextInput/DateTextInput.d.ts +18 -17
- package/dist/components/DatePicker/tests/setup.d.ts +448 -512
- package/dist/components/HeaderToolbar/HeaderToolbar.d.ts +4 -4
- package/dist/components/NirField/NirField.d.ts +29 -34
- package/dist/components/NirField/locales.d.ts +1 -3
- package/dist/components/PasswordField/PasswordField.d.ts +2 -0
- package/dist/components/PeriodField/PeriodField.d.ts +112 -128
- package/dist/components/PhoneField/PhoneField.d.ts +13 -17
- package/dist/components/SearchListField/SearchListField.d.ts +2 -2
- package/dist/components/SyTextArea/SyTextArea.d.ts +0 -4
- package/dist/components/Tables/common/SyTablePagination.d.ts +2 -2
- package/dist/components/index.d.ts +1 -0
- package/dist/composables/validation/useFormValidation.d.ts +10 -0
- package/dist/composables/validation/useValidatable.d.ts +10 -2
- package/dist/design-system-v3.js +126 -125
- package/dist/design-system-v3.umd.cjs +155 -155
- package/dist/main-DISHlqcd.js +34217 -0
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/components/Amelipro/AmeliproFooter/AmeliproFooter.vue +6 -7
- package/src/components/Amelipro/AmeliproFooter/__tests__/AmeliproFooter.spec.ts +787 -0
- package/src/components/Amelipro/AmeliproFooter/__tests__/__snapshots__/AmeliproFooter.spec.ts.snap +318 -0
- package/src/components/Amelipro/AmeliproHeader/AmeliproHeaderBar/AmeliproHeaderBrandSection/__tests__/AmeliproHeaderBrandSection.spec.ts +167 -0
- package/src/components/Amelipro/AmeliproHeader/AmeliproHeaderBar/AmeliproHeaderBrandSection/__tests__/__snapshots__/AmeliproHeaderBrandSection.spec.ts.snap +100 -0
- package/src/components/Amelipro/AmeliproHeader/AmeliproHeaderBar/__tests__/AmeliproHeaderBar.spec.ts +312 -0
- package/src/components/Amelipro/AmeliproHeader/AmeliproHeaderBar/__tests__/__snapshots__/AmeliproHeaderBar.spec.ts.snap +98 -0
- package/src/components/Amelipro/AmeliproHeader/__tests__/AmeliproHeader.spec.ts +361 -0
- package/src/components/Amelipro/AmeliproHeader/__tests__/__snapshots__/AmeliproHeader.spec.ts.snap +22 -0
- package/src/components/Amelipro/AmeliproMenu/__tests__/AmeliproMenu.spec.ts +168 -0
- package/src/components/Amelipro/AmeliproMenu/__tests__/__snapshots__/AmeliproMenu.spec.ts.snap +295 -0
- package/src/components/Amelipro/AmeliproMessagingLayout/AmeliproDropdownMenu/AmeliproDropdownMenuBtn/__tests__/AmeliproDropdownMenuBtn.spec.ts +128 -0
- package/src/components/Amelipro/AmeliproMessagingLayout/AmeliproDropdownMenu/AmeliproDropdownMenuBtn/__tests__/__snapshots__/AmeliproDropdownMenuBtn.spec.ts.snap +67 -0
- package/src/components/Amelipro/AmeliproMessagingLayout/AmeliproDropdownMenu/__tests__/AmeliproDropdownMenu.spec.ts +266 -0
- package/src/components/Amelipro/AmeliproMessagingLayout/AmeliproDropdownMenu/__tests__/__snapshots__/AmeliproDropdownMenu.spec.ts.snap +134 -0
- package/src/components/Amelipro/AmeliproMessagingLayout/AmeliproMessagingMenuBtn/__tests__/AmeliproMessagingMenuBtn.spec.ts +72 -0
- package/src/components/Amelipro/AmeliproMessagingLayout/AmeliproMessagingMenuBtn/__tests__/__snapshots__/AmeliproMessagingMenuBtn.spec.ts.snap +71 -0
- package/src/components/Amelipro/AmeliproPageLayout/tests/__snapshots__/AmeliproPageLayout.spec.ts.snap +12 -0
- package/src/components/Captcha/Captcha.mdx +72 -0
- package/src/components/Captcha/Captcha.stories.ts +276 -0
- package/src/components/Captcha/Captcha.vue +325 -0
- package/src/components/Captcha/CaptchaAlert.vue +60 -0
- package/src/components/Captcha/CaptchaBase.vue +219 -0
- package/src/components/Captcha/CaptchaBtn.vue +35 -0
- package/src/components/Captcha/CaptchaForm.vue +58 -0
- package/src/components/Captcha/CaptchaImg.vue +41 -0
- package/src/components/Captcha/CaptchaInformation.vue +64 -0
- package/src/components/Captcha/captchaApi.ts +111 -0
- package/src/components/Captcha/icons/volumeUp.vue +11 -0
- package/src/components/Captcha/locales.ts +35 -0
- package/src/components/Captcha/readme.md +5 -0
- package/src/components/Captcha/tests/Captcha.spec.ts +298 -0
- package/src/components/Captcha/tests/__snapshots__/Captcha.spec.ts.snap +716 -0
- package/src/components/Captcha/types.ts +2 -0
- package/src/components/Customs/Selects/SySelect/SySelect.vue +2 -2
- package/src/components/Customs/SyCheckbox/SyCheckbox.vue +4 -0
- package/src/components/Customs/SyForm/SyForm.stories.ts +133 -23
- package/src/components/Customs/SyForm/SyForm.vue +17 -1
- package/src/components/Customs/SyTextField/SyTextField.vue +2 -2
- package/src/components/DatePicker/CalendarMode/DatePicker.vue +1 -1
- package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.vue +110 -6
- package/src/components/DatePicker/DateTextInput/DateTextInput.vue +28 -3
- package/src/components/NirField/NirField.stories.ts +74 -0
- package/src/components/NirField/NirField.vue +34 -9
- package/src/components/NirField/locales.ts +1 -3
- package/src/components/PasswordField/PasswordField.vue +39 -7
- package/src/components/PhoneField/PhoneField.vue +43 -10
- package/src/components/index.ts +1 -0
- package/src/composables/validation/useFormValidation.ts +46 -8
- package/src/composables/validation/useValidatable.ts +19 -8
- package/dist/main-DMXtXK3y.js +0 -33458
- package/src/components/Amelipro/AmeliproFooter/tests/AmeliproFooter.spec.ts +0 -15
- package/src/components/Amelipro/AmeliproFooter/tests/__snapshots__/AmeliproFooter.spec.ts.snap +0 -432
- package/src/components/Amelipro/AmeliproHeader/AmeliproHeaderBar/AmeliproHeaderBrandSection/tests/AmeliproHeaderBrandSection.spec.ts +0 -15
- package/src/components/Amelipro/AmeliproHeader/AmeliproHeaderBar/AmeliproHeaderBrandSection/tests/__snapshots__/AmeliproHeaderBrandSection.spec.ts.snap +0 -131
- package/src/components/Amelipro/AmeliproHeader/AmeliproHeaderBar/tests/AmeliproHeaderBar.spec.ts +0 -15
- package/src/components/Amelipro/AmeliproHeader/AmeliproHeaderBar/tests/__snapshots__/AmeliproHeaderBar.spec.ts.snap +0 -172
- package/src/components/Amelipro/AmeliproHeader/tests/AmeliproHeader.spec.ts +0 -159
- package/src/components/Amelipro/AmeliproHeader/tests/__snapshots__/AmeliproHeader.spec.ts.snap +0 -841
- package/src/components/Amelipro/AmeliproMenu/tests/AmeliproMenu.spec.ts +0 -85
- package/src/components/Amelipro/AmeliproMenu/tests/__snapshots__/AmeliproMenu.spec.ts.snap +0 -537
- package/src/components/Amelipro/AmeliproMessagingLayout/AmeliproDropdownMenu/AmeliproDropdownMenuBtn/tests/AmeliproDropdownMenuBtn.spec.ts +0 -16
- package/src/components/Amelipro/AmeliproMessagingLayout/AmeliproDropdownMenu/AmeliproDropdownMenuBtn/tests/__snapshots__/AmeliproDropdownMenuBtn.spec.ts.snap +0 -56
- package/src/components/Amelipro/AmeliproMessagingLayout/AmeliproDropdownMenu/tests/AmeliproDropdownMenu.spec.ts +0 -28
- package/src/components/Amelipro/AmeliproMessagingLayout/AmeliproDropdownMenu/tests/__snapshots__/AmeliproDropdownMenu.spec.ts.snap +0 -300
- package/src/components/Amelipro/AmeliproMessagingLayout/AmeliproMessagingMenuBtn/tests/AmeliproMessagingMenuBtn.spec.ts +0 -16
- package/src/components/Amelipro/AmeliproMessagingLayout/AmeliproMessagingMenuBtn/tests/__snapshots__/AmeliproMessagingMenuBtn.spec.ts.snap +0 -89
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { onMounted, ref, watch } from 'vue'
|
|
3
|
+
import {
|
|
4
|
+
createCaptchaAudio,
|
|
5
|
+
createCaptchaImage,
|
|
6
|
+
getCaptchaAudioUrl,
|
|
7
|
+
getCaptchaImageUrl,
|
|
8
|
+
} from './captchaApi'
|
|
9
|
+
import type { CaptchaType, StateType } from './types'
|
|
10
|
+
import type { locales as defaultLocales } from './locales'
|
|
11
|
+
|
|
12
|
+
const props = defineProps<{
|
|
13
|
+
modelValue: CaptchaType
|
|
14
|
+
urlCreate: string
|
|
15
|
+
urlGetImage: string
|
|
16
|
+
urlGetAudio: string
|
|
17
|
+
locales: typeof defaultLocales
|
|
18
|
+
}>()
|
|
19
|
+
|
|
20
|
+
const emit = defineEmits<{
|
|
21
|
+
(e: 'update:modelValue', modelValue: CaptchaType): void
|
|
22
|
+
(e: 'create-captcha:init'): void
|
|
23
|
+
(e: 'create-captcha:error', error: Error): void
|
|
24
|
+
(e: 'create-captcha:success', id: string | null): void
|
|
25
|
+
}>()
|
|
26
|
+
|
|
27
|
+
const type = ref<CaptchaType>(props.modelValue)
|
|
28
|
+
const id = ref<string | null>(null)
|
|
29
|
+
const url = ref<string | null>(null)
|
|
30
|
+
const audioElement = ref<HTMLAudioElement | null>(null)
|
|
31
|
+
const isPlaying = ref(false)
|
|
32
|
+
const isError = ref(false)
|
|
33
|
+
const errorMessage = ref<string | null>(null)
|
|
34
|
+
const state = ref<StateType>('idle')
|
|
35
|
+
|
|
36
|
+
onMounted(async () => {
|
|
37
|
+
await chooseType(props.modelValue)
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
watch(() => props.modelValue, async (newType) => {
|
|
41
|
+
if (type.value !== newType) {
|
|
42
|
+
type.value = newType
|
|
43
|
+
await chooseType(newType)
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
async function chooseType(selectedType: CaptchaType) {
|
|
48
|
+
updateType(selectedType)
|
|
49
|
+
resetError()
|
|
50
|
+
|
|
51
|
+
switch (selectedType) {
|
|
52
|
+
case 'image':
|
|
53
|
+
createImage()
|
|
54
|
+
break
|
|
55
|
+
case 'audio':
|
|
56
|
+
createAudio()
|
|
57
|
+
break
|
|
58
|
+
default:
|
|
59
|
+
break
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function chooseImage() {
|
|
64
|
+
chooseType('image')
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function chooseAudio() {
|
|
68
|
+
chooseType('audio')
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function createImage() {
|
|
72
|
+
emitCreateInitEvent()
|
|
73
|
+
resetValues()
|
|
74
|
+
|
|
75
|
+
createCaptchaImage(
|
|
76
|
+
props.urlCreate,
|
|
77
|
+
(captchaId: string) => {
|
|
78
|
+
id.value = captchaId
|
|
79
|
+
url.value = getCaptchaImageUrl(props.urlGetImage, captchaId)
|
|
80
|
+
emitCreateSuccessEvent()
|
|
81
|
+
state.value = 'resolved'
|
|
82
|
+
},
|
|
83
|
+
onCreateCaptchaError,
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function createAudio() {
|
|
88
|
+
emitCreateInitEvent()
|
|
89
|
+
resetValues()
|
|
90
|
+
|
|
91
|
+
createCaptchaAudio(
|
|
92
|
+
props.urlCreate,
|
|
93
|
+
(captchaId: string) => {
|
|
94
|
+
id.value = captchaId
|
|
95
|
+
url.value = getCaptchaAudioUrl(props.urlGetAudio, captchaId)
|
|
96
|
+
|
|
97
|
+
audioElement.value = new Audio(url.value)
|
|
98
|
+
audioElement.value.addEventListener('ended', () => {
|
|
99
|
+
isPlaying.value = false
|
|
100
|
+
})
|
|
101
|
+
audioElement.value.addEventListener('error', () => {
|
|
102
|
+
onCreateCaptchaError(new Error('Audio failed to load'))
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
emitCreateSuccessEvent()
|
|
106
|
+
state.value = 'resolved'
|
|
107
|
+
},
|
|
108
|
+
onCreateCaptchaError,
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function resetValues() {
|
|
113
|
+
// Stop audio and clean up in a safe order
|
|
114
|
+
if (audioElement.value) {
|
|
115
|
+
try {
|
|
116
|
+
audioElement.value.pause()
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
// Ignore errors if audio element is already disposed
|
|
120
|
+
}
|
|
121
|
+
audioElement.value = null
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
url.value = null
|
|
125
|
+
id.value = null
|
|
126
|
+
state.value = 'pending'
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function resetError() {
|
|
130
|
+
isError.value = false
|
|
131
|
+
errorMessage.value = null
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function toggleAudio() {
|
|
135
|
+
if (!audioElement.value) return
|
|
136
|
+
|
|
137
|
+
if (isPlaying.value) {
|
|
138
|
+
audioElement.value.pause()
|
|
139
|
+
isPlaying.value = false
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
audioElement.value.play()
|
|
143
|
+
isPlaying.value = true
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function onCreateCaptchaError(error: Error) {
|
|
148
|
+
isError.value = true
|
|
149
|
+
|
|
150
|
+
try {
|
|
151
|
+
errorMessage.value = JSON.parse(error.message)
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
errorMessage.value = props.locales.defaultErrorMessage
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
emitCreateErrorEvent(error)
|
|
158
|
+
state.value = 'rejected'
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function updateType(selectedType: CaptchaType) {
|
|
162
|
+
type.value = selectedType
|
|
163
|
+
emitTypeChangeEvent(selectedType)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function emitTypeChangeEvent(newType: CaptchaType) {
|
|
167
|
+
emit('update:modelValue', newType)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function emitCreateInitEvent() {
|
|
171
|
+
emit('create-captcha:init')
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function emitCreateErrorEvent(error: Error) {
|
|
175
|
+
emit('create-captcha:error', error)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function emitCreateSuccessEvent() {
|
|
179
|
+
emit('create-captcha:success', id.value)
|
|
180
|
+
}
|
|
181
|
+
</script>
|
|
182
|
+
|
|
183
|
+
<template>
|
|
184
|
+
<div class="captcha">
|
|
185
|
+
<slot
|
|
186
|
+
v-if="type === 'image'"
|
|
187
|
+
name="image"
|
|
188
|
+
:choose-image="chooseImage"
|
|
189
|
+
:choose-audio="chooseAudio"
|
|
190
|
+
:url="url"
|
|
191
|
+
:is-error="isError"
|
|
192
|
+
:error-message="errorMessage"
|
|
193
|
+
:state="state"
|
|
194
|
+
/>
|
|
195
|
+
|
|
196
|
+
<slot
|
|
197
|
+
v-else-if="type === 'audio'"
|
|
198
|
+
name="audio"
|
|
199
|
+
:choose-image="chooseImage"
|
|
200
|
+
:choose-audio="chooseAudio"
|
|
201
|
+
:toggle-audio="toggleAudio"
|
|
202
|
+
:url="url"
|
|
203
|
+
:is-error="isError"
|
|
204
|
+
:error-message="errorMessage"
|
|
205
|
+
:is-playing="isPlaying"
|
|
206
|
+
:state="state"
|
|
207
|
+
/>
|
|
208
|
+
|
|
209
|
+
<slot
|
|
210
|
+
v-else
|
|
211
|
+
name="default"
|
|
212
|
+
:choose-image="chooseImage"
|
|
213
|
+
:choose-audio="chooseAudio"
|
|
214
|
+
:is-error="isError"
|
|
215
|
+
:error-message="errorMessage"
|
|
216
|
+
:state="state"
|
|
217
|
+
/>
|
|
218
|
+
</div>
|
|
219
|
+
</template>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import SyIcon from '../Customs/SyIcon/SyIcon.vue'
|
|
3
|
+
|
|
4
|
+
defineProps<{
|
|
5
|
+
prependIcon?: string
|
|
6
|
+
}>()
|
|
7
|
+
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<button
|
|
12
|
+
class="captcha-btn text-primary"
|
|
13
|
+
type="button"
|
|
14
|
+
>
|
|
15
|
+
<SyIcon
|
|
16
|
+
v-if="prependIcon"
|
|
17
|
+
size="x-small"
|
|
18
|
+
:icon="prependIcon"
|
|
19
|
+
decorative
|
|
20
|
+
/>
|
|
21
|
+
<slot />
|
|
22
|
+
</button>
|
|
23
|
+
</template>
|
|
24
|
+
|
|
25
|
+
<style scoped lang="scss">
|
|
26
|
+
.captcha-btn {
|
|
27
|
+
cursor: pointer;
|
|
28
|
+
display: flex;
|
|
29
|
+
align-items: center;
|
|
30
|
+
gap: 4px;
|
|
31
|
+
padding: 4px 8px;
|
|
32
|
+
font-weight: 700;
|
|
33
|
+
font-size: 0.875rem;
|
|
34
|
+
}
|
|
35
|
+
</style>
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref, watch } from 'vue'
|
|
3
|
+
import SyTextField from '../Customs/SyTextField/SyTextField.vue'
|
|
4
|
+
import type { locales as defaultLocales } from './locales'
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
label: string
|
|
8
|
+
modelValue?: string | null
|
|
9
|
+
state?: string | null
|
|
10
|
+
loading?: boolean
|
|
11
|
+
errors: string[] | undefined
|
|
12
|
+
success: boolean
|
|
13
|
+
locales: typeof defaultLocales
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const props = defineProps<Props>()
|
|
17
|
+
const emit = defineEmits(['update:modelValue'])
|
|
18
|
+
|
|
19
|
+
const text = ref<string | null>(props.modelValue ?? null)
|
|
20
|
+
|
|
21
|
+
watch(() => props.modelValue, (newVal) => {
|
|
22
|
+
text.value = newVal ?? null
|
|
23
|
+
}, { immediate: true })
|
|
24
|
+
|
|
25
|
+
function emitChangeEvent() {
|
|
26
|
+
emit('update:modelValue', text.value)
|
|
27
|
+
}
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<template>
|
|
31
|
+
<VSheet>
|
|
32
|
+
<SyTextField
|
|
33
|
+
v-model="text"
|
|
34
|
+
class="mt-4"
|
|
35
|
+
variant="outlined"
|
|
36
|
+
:error-messages="props.errors"
|
|
37
|
+
:custom-rules="[
|
|
38
|
+
{
|
|
39
|
+
type: 'required',
|
|
40
|
+
options: { message: locales.required },
|
|
41
|
+
}
|
|
42
|
+
]"
|
|
43
|
+
:show-success-messages="false"
|
|
44
|
+
:has-success="success"
|
|
45
|
+
:disabled="state === 'rejected'"
|
|
46
|
+
:label="label"
|
|
47
|
+
hide-details="auto"
|
|
48
|
+
:readonly="success"
|
|
49
|
+
:is-clearable="!success"
|
|
50
|
+
@update:model-value="emitChangeEvent"
|
|
51
|
+
/>
|
|
52
|
+
</VSheet>
|
|
53
|
+
</template>
|
|
54
|
+
<style lang="scss" scoped>
|
|
55
|
+
:deep(.v-input__control:not(:has(.v-field--error))+.v-input__details) {
|
|
56
|
+
display: none;
|
|
57
|
+
}
|
|
58
|
+
</style>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { locales as defaultLocales } from './locales'
|
|
3
|
+
|
|
4
|
+
defineProps<{
|
|
5
|
+
state: string
|
|
6
|
+
src?: string | null
|
|
7
|
+
locales: typeof defaultLocales
|
|
8
|
+
}>()
|
|
9
|
+
|
|
10
|
+
defineEmits<{
|
|
11
|
+
(e: 'imageError'): void
|
|
12
|
+
}>()
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<template>
|
|
16
|
+
<div>
|
|
17
|
+
<VSkeletonLoader
|
|
18
|
+
v-if="state === 'pending'"
|
|
19
|
+
:aria-label="locales.captchaImgLoading"
|
|
20
|
+
type="image"
|
|
21
|
+
height="64"
|
|
22
|
+
width="311"
|
|
23
|
+
tile
|
|
24
|
+
/>
|
|
25
|
+
|
|
26
|
+
<img
|
|
27
|
+
v-else
|
|
28
|
+
height="64"
|
|
29
|
+
width="311"
|
|
30
|
+
:alt="locales.captchaImgAlt"
|
|
31
|
+
:src="src as string"
|
|
32
|
+
@error="$emit('imageError')"
|
|
33
|
+
>
|
|
34
|
+
</div>
|
|
35
|
+
</template>
|
|
36
|
+
|
|
37
|
+
<style lang="scss" scoped>
|
|
38
|
+
:deep(.v-skeleton-loader__image) {
|
|
39
|
+
height: 100%;
|
|
40
|
+
}
|
|
41
|
+
</style>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { CaptchaType } from './types'
|
|
3
|
+
import type { locales as defaultLocales } from './locales'
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
type?: CaptchaType | string
|
|
7
|
+
tagTitle?: string
|
|
8
|
+
locales: typeof defaultLocales
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
withDefaults(defineProps<Props>(), {
|
|
12
|
+
type: undefined,
|
|
13
|
+
tagTitle: 'h3',
|
|
14
|
+
})
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<template>
|
|
18
|
+
<div>
|
|
19
|
+
<div class="d-flex flex-row align-center">
|
|
20
|
+
<component
|
|
21
|
+
:is="tagTitle"
|
|
22
|
+
class="captcha-title text-textBase"
|
|
23
|
+
>
|
|
24
|
+
{{ locales.information.securityCheck }}
|
|
25
|
+
</component>
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<div
|
|
29
|
+
v-if="type"
|
|
30
|
+
>
|
|
31
|
+
<div v-if="type === 'image'">
|
|
32
|
+
<p class="captcha-instructions text-textSubdued">
|
|
33
|
+
{{ locales.information.imageInstruction }}
|
|
34
|
+
</p>
|
|
35
|
+
|
|
36
|
+
<slot name="error" />
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
<div v-if="type === 'audio'">
|
|
40
|
+
<p class="captcha-instructions text-textSubdued">
|
|
41
|
+
{{ locales.information.audioInstruction }}
|
|
42
|
+
</p>
|
|
43
|
+
|
|
44
|
+
<slot name="error" />
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
</template>
|
|
49
|
+
|
|
50
|
+
<style lang="scss" scoped>
|
|
51
|
+
.captcha-title {
|
|
52
|
+
font-weight: 700;
|
|
53
|
+
font-size: 1.125rem;
|
|
54
|
+
line-height: 150%;
|
|
55
|
+
margin: 0;
|
|
56
|
+
padding: 0;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.captcha-instructions {
|
|
60
|
+
font-size: 1rem;
|
|
61
|
+
line-height: 150%;
|
|
62
|
+
font-weight: 400;
|
|
63
|
+
}
|
|
64
|
+
</style>
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
const reGet = /CAPTCHAID/
|
|
2
|
+
|
|
3
|
+
type SuccessCallback = (captchaId: string) => void
|
|
4
|
+
type ErrorCallback = (error: Error) => void
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Création du captcha auprès d'OBS
|
|
8
|
+
* @param urlCreate - URL de création
|
|
9
|
+
* @param body - Corps de la requête (peut être un Document ou un BodyInit)
|
|
10
|
+
* @param cbsuccess - Fonction à appeler en cas de succès
|
|
11
|
+
* @param cberror - Fonction à appeler en cas d'erreur
|
|
12
|
+
*/
|
|
13
|
+
export function createCaptcha(
|
|
14
|
+
urlCreate: string,
|
|
15
|
+
body: string | null,
|
|
16
|
+
cbsuccess: SuccessCallback,
|
|
17
|
+
cberror: ErrorCallback,
|
|
18
|
+
): void {
|
|
19
|
+
fetch(urlCreate, {
|
|
20
|
+
method: 'POST',
|
|
21
|
+
headers: {
|
|
22
|
+
'Content-Type': 'application/json',
|
|
23
|
+
},
|
|
24
|
+
body: body,
|
|
25
|
+
})
|
|
26
|
+
.then(async (response) => {
|
|
27
|
+
if (response.ok) {
|
|
28
|
+
try {
|
|
29
|
+
const json = await response.json()
|
|
30
|
+
cbsuccess(json.id)
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
cberror(err as Error)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
cberror(response.statusText ? new Error(response.statusText) : new Error('Erreur inconnue'))
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
.catch((error) => {
|
|
41
|
+
cberror(error)
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Création d'un captcha image auprès d'OBS avec locale par défaut
|
|
47
|
+
* @param urlCreate - URL de création
|
|
48
|
+
* @param cbsuccess - Callback de succès
|
|
49
|
+
* @param cberror - Callback d'erreur
|
|
50
|
+
* @param locale - Locale (langue)
|
|
51
|
+
*/
|
|
52
|
+
export function createCaptchaImage(
|
|
53
|
+
urlCreate: string,
|
|
54
|
+
cbsuccess: SuccessCallback,
|
|
55
|
+
cberror: ErrorCallback,
|
|
56
|
+
locale: string = 'default',
|
|
57
|
+
): void {
|
|
58
|
+
const body = JSON.stringify({
|
|
59
|
+
type: 'IMAGE',
|
|
60
|
+
locale,
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
createCaptcha(urlCreate, body, cbsuccess, cberror)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Création d'un captcha audio auprès d'OBS
|
|
68
|
+
* @param urlCreate - URL de création
|
|
69
|
+
* @param cbsuccess - Callback de succès
|
|
70
|
+
* @param cberror - Callback d'erreur
|
|
71
|
+
* @param locale - Locale (langue), "default" si non indiqué
|
|
72
|
+
*/
|
|
73
|
+
export function createCaptchaAudio(
|
|
74
|
+
urlCreate: string,
|
|
75
|
+
cbsuccess: SuccessCallback,
|
|
76
|
+
cberror: ErrorCallback,
|
|
77
|
+
locale: string = 'default',
|
|
78
|
+
): void {
|
|
79
|
+
const body = JSON.stringify({
|
|
80
|
+
type: 'AUDIO',
|
|
81
|
+
locale,
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
createCaptcha(urlCreate, body, cbsuccess, cberror)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Génère l'URL de récupération de l'image du captcha
|
|
89
|
+
* @param urlGetImage - URL avec le placeholder CAPTCHAID
|
|
90
|
+
* @param captchaId - Identifiant du captcha
|
|
91
|
+
* @returns L'URL avec l'identifiant inséré
|
|
92
|
+
*/
|
|
93
|
+
export function getCaptchaImageUrl(
|
|
94
|
+
urlGetImage: string,
|
|
95
|
+
captchaId: string,
|
|
96
|
+
): string {
|
|
97
|
+
return urlGetImage.replace(reGet, captchaId)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Génère l'URL de récupération de l'audio du captcha
|
|
102
|
+
* @param urlGetAudio - URL avec le placeholder CAPTCHAID
|
|
103
|
+
* @param captchaId - Identifiant du captcha
|
|
104
|
+
* @returns L'URL avec l'identifiant inséré
|
|
105
|
+
*/
|
|
106
|
+
export function getCaptchaAudioUrl(
|
|
107
|
+
urlGetAudio: string,
|
|
108
|
+
captchaId: string,
|
|
109
|
+
): string {
|
|
110
|
+
return urlGetAudio.replace(reGet, captchaId)
|
|
111
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<svg
|
|
3
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
4
|
+
height="24px"
|
|
5
|
+
viewBox="0 -960 960 960"
|
|
6
|
+
width="24px"
|
|
7
|
+
fill="#1f1f1f"
|
|
8
|
+
>
|
|
9
|
+
<path d="M560-131v-82q90-26 145-100t55-168q0-94-55-168T560-749v-82q124 28 202 125.5T840-481q0 127-78 224.5T560-131ZM120-360v-240h160l200-200v640L280-360H120Zm440 40v-322q47 22 73.5 66t26.5 96q0 51-26.5 94.5T560-320ZM400-606l-86 86H200v80h114l86 86v-252ZM300-480Z" />
|
|
10
|
+
</svg>
|
|
11
|
+
</template>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export const locales = {
|
|
2
|
+
hardToRead: 'Vous n\'arrivez pas à lire ?',
|
|
3
|
+
image: {
|
|
4
|
+
new: 'Changer d’image',
|
|
5
|
+
change: 'Utiliser un captcha audio',
|
|
6
|
+
textfieldLabel: 'Caractères de l’image',
|
|
7
|
+
},
|
|
8
|
+
audio: {
|
|
9
|
+
new: 'Changer d’audio',
|
|
10
|
+
change: 'Utiliser un captcha image',
|
|
11
|
+
textfieldLabel: 'Caractères de l’audio',
|
|
12
|
+
loading: 'Chargement de l\'audio du captcha',
|
|
13
|
+
},
|
|
14
|
+
choiceCaptcha: {
|
|
15
|
+
image: 'captcha image',
|
|
16
|
+
audio: 'captcha audio',
|
|
17
|
+
},
|
|
18
|
+
helpDesk: (phoneNumber: string) => `Si vous êtes en incapacité de résoudre le captcha, contactez le support au ${phoneNumber}.`,
|
|
19
|
+
pause: 'Pause',
|
|
20
|
+
play: 'Lire l\'audio',
|
|
21
|
+
renew: 'Renouveler le captcha',
|
|
22
|
+
validate: 'Vérifier',
|
|
23
|
+
captchaImgLoading: 'Chargement de l\'image du captcha',
|
|
24
|
+
captchaImgAlt: 'Le captcha à saisir',
|
|
25
|
+
information: {
|
|
26
|
+
securityCheck: 'Vérification de sécurité',
|
|
27
|
+
btnAriaLabel: 'Ouvrir la bulle d’information',
|
|
28
|
+
tooltip: 'Nous nous assurons ainsi que vous êtes un être humain, et non un robot.',
|
|
29
|
+
imageInstruction: 'Saisissez les caractères affichés ci-dessous.',
|
|
30
|
+
audioInstruction: 'Saisissez le texte que vous entendez.',
|
|
31
|
+
},
|
|
32
|
+
defaultErrorMessage: 'Une erreur inconnue est survenue',
|
|
33
|
+
required: 'Le captcha est requis',
|
|
34
|
+
choiceCaptchaTitle: 'Choisissez le type de captcha de votre choix.',
|
|
35
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
https://gitlab.cnqd.cnamts.fr/captcha/capt_x
|
|
2
|
+
http://pad-st.cnamts.fr/pad-ddst/fabricant/dait/captcha/fiche-resume.html
|
|
3
|
+
http://pad-st.cnamts.fr/pad-ddst/fabricant/dait/captcha/demo/captcha.html
|
|
4
|
+
https://gitlab.cnqd.cnamts.fr/captcha/captcha-vue-design-system
|
|
5
|
+
https://gitlab.cnqd.cnamts.fr/captcha/captchavue
|