Skip to content

Commit 77dc97b

Browse files
committed
feat: added utility class
1 parent 61219a7 commit 77dc97b

File tree

6 files changed

+95
-29
lines changed

6 files changed

+95
-29
lines changed

README.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,15 @@ Component appends captcha script into head section of application. If you alread
112112
</template>
113113
```
114114

115+
> Package checks if `window.smartCaptcha` object was defined. However when using multiple captcha instances at once all of them will have `window.smartCaptcha === undefined` on initial load. Therefore it is better either load script on your own and disable widget loading for every captcha or disable it for every captcha but first, e.g.
116+
117+
```vue
118+
<template>
119+
<SmartCaptcha />
120+
<SmartCaptcha :load-widget="false" />
121+
</template>
122+
```
123+
115124
### Rendering timeout
116125

117126
On a mount component will try to resolve global `window.smartCaptcha` object. If it was not defined component will "die". You may set `timeout` property in milliseconds to specify amount of time package will try to resolve this object
@@ -250,6 +259,18 @@ const captcha = useSmartCaptcha(container, {
250259
}, false)
251260
```
252261

262+
> Package checks if `window.smartCaptcha` object was defined. However when using multiple captcha instances at once all of them will have `window.smartCaptcha === undefined` on initial load.. Therefore it is better either load script on your own and disable widget loading for every captcha or disable it for every captcha but first, e.g.
263+
264+
```js
265+
const firstCaptcha = useSmartCaptcha(container, {
266+
// render props
267+
})
268+
269+
const secondCaptcha = useSmartCaptcha(container, {
270+
// render props
271+
}, false) // disable script appending as it will be appended by first captcha
272+
```
273+
253274
### Rendering timeout
254275

255276
When being called composable will try to resolve global `window.smartCaptcha` object. If it was not defined component will "die". You may set `timeout` as fourth argument in milliseconds to specify amount of time package will try to resolve this object
@@ -408,6 +429,19 @@ const onCaptchaFired = async (tkn: Token) => {
408429
</script>
409430
```
410431

432+
## Utilities
433+
434+
Package provides utility class with every method but `render` in order if you need call captcha methods "manually" outside of current captcha (since both composable and captcha do not allows you to specify "custom" widget id)
435+
436+
```js
437+
import { SmartCaptchaUtils } from 'vue3-smart-captcha'
438+
439+
const widgetId = 0 // example
440+
const utils = new SmartCaptchaUtils()
441+
442+
utils.execute(widgetId)
443+
```
444+
411445
## License
412446

413447
Open-source under [MIT license](LICENSE)

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"vue3"
1010
],
1111
"license": "MIT",
12-
"version": "1.0.0",
12+
"version": "1.1.0",
1313
"type": "module",
1414
"main": "./dist/index.cjs",
1515
"module": "./dist/index.js",

src/composables/useSmartCaptcha.ts

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,31 @@
11
import { onMounted, onUnmounted, ref, type Ref } from 'vue'
22
import type {
3-
BaseEventCallback,
4-
JavascriptErrorEventCallback,
3+
CaptchaSubscriptionEventCallback,
54
SmartCaptchaRenderProps,
65
SubscribeEvent,
7-
SuccessEventCallback,
86
Token,
97
WidgetId,
108
} from '@/types/smartcaptcha'
9+
import SmartCaptchaUtils from '@/utils/smartcaptcha'
1110

1211
type RenderProps = Partial<SmartCaptchaRenderProps> | string
1312
type CaptchaContainer = Ref | HTMLElement | string
14-
type CaptchaSubscriptionEventCallback = BaseEventCallback | SuccessEventCallback | JavascriptErrorEventCallback
1513

1614
export const useSmartCaptcha = (container: CaptchaContainer, renderProps?: RenderProps, load = true, timeout = 2000) => {
15+
const utils = new SmartCaptchaUtils()
16+
1717
const widgetId = ref<WidgetId>()
1818
const token = ref<Token>()
1919

2020
const __container = ref()
21-
const __scriptWasAppended = ref(false)
2221

2322
const __subscriptions: Record<SubscribeEvent, CaptchaSubscriptionEventCallback[]> = {
24-
success: [] as SuccessEventCallback[],
25-
'javascript-error': [] as JavascriptErrorEventCallback[],
26-
'network-error': [] as BaseEventCallback[],
27-
'token-expired': [] as BaseEventCallback[],
28-
'challenge-hidden': [] as BaseEventCallback[],
29-
'challenge-visible': [] as BaseEventCallback[],
23+
success: [],
24+
'javascript-error': [],
25+
'network-error': [],
26+
'token-expired': [],
27+
'challenge-hidden': [],
28+
'challenge-visible': [],
3029
}
3130

3231
const __setContainer = () => {
@@ -41,14 +40,12 @@ export const useSmartCaptcha = (container: CaptchaContainer, renderProps?: Rende
4140

4241
const __addScript = () => {
4342
const scriptElement = document.createElement('script')
44-
scriptElement.src = 'https://smartcaptcha.yandexcloud.net/captcha.js?render=onload'
43+
scriptElement.src = utils.SCRIPT_RENDER_ONLOAD_SRC
4544
scriptElement.defer = true
4645
scriptElement.type = 'text/javascript'
4746
scriptElement.crossOrigin = 'anonymous'
4847
scriptElement.dataset.captcha = 'true'
4948
document.head.appendChild(scriptElement)
50-
51-
__scriptWasAppended.value = true
5249
}
5350

5451
const __renderProps = (): SmartCaptchaRenderProps => {
@@ -64,7 +61,7 @@ export const useSmartCaptcha = (container: CaptchaContainer, renderProps?: Rende
6461

6562
return {
6663
...renderProps,
67-
sitekey, // the only required parameter
64+
sitekey,
6865
}
6966
}
7067

@@ -75,9 +72,7 @@ export const useSmartCaptcha = (container: CaptchaContainer, renderProps?: Rende
7572
const __subscribeToCaptchaEvent = (event: SubscribeEvent) => {
7673
if (__subscriptions[event].length > 0) {
7774
__subscriptions[event].forEach(cb => {
78-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
79-
// @ts-ignore Yelling because of callback type
80-
window.smartCaptcha?.subscribe(widgetId.value as WidgetId, event, cb)
75+
utils.subscribe(widgetId.value as WidgetId, event, cb)
8176
})
8277
}
8378
}
@@ -88,7 +83,7 @@ export const useSmartCaptcha = (container: CaptchaContainer, renderProps?: Rende
8883
}
8984

9085
// Required to set token value
91-
window.smartCaptcha?.subscribe(widgetId.value, 'success', __onSuccess)
86+
utils.subscribe(widgetId.value, 'success', __onSuccess)
9287

9388
Array.from(Object.keys(__subscriptions) as SubscribeEvent[]).forEach(event => {
9489
__subscribeToCaptchaEvent(event)
@@ -112,7 +107,8 @@ export const useSmartCaptcha = (container: CaptchaContainer, renderProps?: Rende
112107
onMounted(() => {
113108
__setContainer()
114109

115-
if (! __scriptWasAppended.value && load) {
110+
// Try not to load multiple instances per time
111+
if (window.smartCaptcha === undefined && load) {
116112
__addScript()
117113
}
118114

@@ -145,24 +141,27 @@ export const useSmartCaptcha = (container: CaptchaContainer, renderProps?: Rende
145141
})
146142

147143
const execute = () => {
148-
window.smartCaptcha?.execute(widgetId.value)
144+
utils.execute(widgetId.value)
149145
}
150146

151-
const reset = () => {
152-
window.smartCaptcha?.reset(widgetId.value)
153-
147+
const __reset = () => {
154148
widgetId.value = undefined
155149
token.value = undefined
156150
}
157151

152+
const reset = () => {
153+
utils.reset(widgetId.value)
154+
155+
__reset()
156+
}
157+
158158
const destroy = () => {
159-
window.smartCaptcha?.destroy(widgetId.value)
159+
utils.destroy(widgetId.value)
160160

161-
widgetId.value = undefined
162-
token.value = undefined
161+
__reset()
163162
}
164163

165-
const getResponse = (): Token | undefined => window.smartCaptcha?.getResponse(widgetId.value)
164+
const getResponse = (): Token | undefined => utils.getResponse(widgetId.value)
166165

167166
const subscribeTo = <T extends CaptchaSubscriptionEventCallback>(event: SubscribeEvent, cb: T) => {
168167
__subscriptions[event].push(cb)

src/plugin.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import SmartCaptcha from '@/components/SmartCaptcha.vue'
22
import { useSmartCaptcha } from '@/composables/useSmartCaptcha'
3+
import SmartCaptchaUtils from '@/utils/smartcaptcha'
34
import type { Plugin } from 'vue'
45
import type {
56
SmartCaptcha as WindowSmartCaptcha,
@@ -19,6 +20,7 @@ export {
1920
SmartCaptcha, // to keep backward compatibility
2021
SmartCaptchaPlugin,
2122
useSmartCaptcha,
23+
SmartCaptchaUtils,
2224
type WindowSmartCaptcha,
2325
type WidgetId,
2426
type Token,

src/types/smartcaptcha.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ export type BaseEventCallback = () => void
4949
export type SuccessEventCallback = (token: Token) => void
5050
export type JavascriptError = { filename: string, message: string, col: number, line: number }
5151
export type JavascriptErrorEventCallback = (error: JavascriptError) => void
52+
export type CaptchaSubscriptionEventCallback = BaseEventCallback | SuccessEventCallback | JavascriptErrorEventCallback
5253

5354
/**
5455
* @link https://cloud.yandex.ru/docs/smartcaptcha/concepts/widget-methods#methods

src/utils/smartcaptcha.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import type { SubscribeEvent, Token, WidgetId, CaptchaSubscriptionEventCallback } from '@/types/smartcaptcha'
2+
3+
class SmartCaptchaUtils
4+
{
5+
readonly SCRIPT_RENDER_ONLOAD_SRC = 'https://smartcaptcha.yandexcloud.net/captcha.js?render=onload'
6+
7+
execute (widgetID?: WidgetId) {
8+
window.smartCaptcha?.execute(widgetID)
9+
}
10+
11+
reset (widgetID?: WidgetId) {
12+
window.smartCaptcha?.reset(widgetID)
13+
}
14+
15+
destroy (widgetID?: WidgetId) {
16+
window.smartCaptcha?.destroy(widgetID)
17+
}
18+
19+
getResponse(widgetID?: WidgetId): Token | undefined {
20+
return window.smartCaptcha?.getResponse(widgetID)
21+
}
22+
23+
subscribe(widgetId: WidgetId, event: SubscribeEvent, cb: CaptchaSubscriptionEventCallback) {
24+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
25+
// @ts-ignore Yelling because of callback type
26+
window.smartCaptcha?.subscribe(widgetId, event, cb)
27+
}
28+
}
29+
30+
export default SmartCaptchaUtils

0 commit comments

Comments
 (0)