merge upstream 2025-02-03

This commit is contained in:
Hazelnoot 2025-02-03 14:31:26 -05:00
commit a4e86758c1
264 changed files with 15775 additions and 4919 deletions

View file

@ -30,6 +30,9 @@ import { ref, shallowRef, computed, onMounted, onBeforeUnmount, watch, onUnmount
import { defaultStore } from '@/store.js';
// APIs provided by Captcha services
// see: https://docs.hcaptcha.com/configuration/#javascript-api
// see: https://developers.google.com/recaptcha/docs/display?hl=ja
// see: https://developers.cloudflare.com/turnstile/get-started/client-side-rendering/#explicitly-render-the-turnstile-widget
export type Captcha = {
render(container: string | Node, options: {
readonly [_ in 'sitekey' | 'theme' | 'type' | 'size' | 'tabindex' | 'callback' | 'expired' | 'expired-callback' | 'error-callback' | 'endpoint']?: unknown;
@ -56,6 +59,7 @@ declare global {
const props = defineProps<{
provider: CaptchaProvider;
sitekey: string | null; // null will show error on request
secretKey?: string | null;
instanceUrl?: string | null;
modelValue?: string | null;
}>();
@ -67,7 +71,7 @@ const emit = defineEmits<{
const available = ref(false);
const captchaEl = shallowRef<HTMLDivElement | undefined>();
const captchaWidgetId = ref<string | undefined>(undefined);
const testcaptchaInput = ref('');
const testcaptchaPassed = ref(false);
@ -99,6 +103,15 @@ const scriptId = computed(() => `script-${props.provider}`);
const captcha = computed<Captcha>(() => window[variable.value] || {} as unknown as Captcha);
watch(() => [props.instanceUrl, props.sitekey, props.secretKey], async () => {
//
if (available.value) {
callback(undefined);
clearWidget();
await requestRender();
}
});
if (loaded || props.provider === 'mcaptcha' || props.provider === 'testcaptcha') {
available.value = true;
} else if (src.value !== null) {
@ -111,14 +124,38 @@ if (loaded || props.provider === 'mcaptcha' || props.provider === 'testcaptcha')
}
function reset() {
if (captcha.value.reset) captcha.value.reset();
if (captcha.value.reset && captchaWidgetId.value !== undefined) {
try {
captcha.value.reset(captchaWidgetId.value);
} catch (error: unknown) {
// ignore
if (_DEV_) console.warn(error);
}
}
testcaptchaPassed.value = false;
testcaptchaInput.value = '';
}
function remove() {
if (captcha.value.remove && captchaWidgetId.value) {
try {
if (_DEV_) console.log('remove', props.provider, captchaWidgetId.value);
captcha.value.remove(captchaWidgetId.value);
} catch (error: unknown) {
// ignore
if (_DEV_) console.warn(error);
}
}
}
async function requestRender() {
if (captcha.value.render && captchaEl.value instanceof Element) {
captcha.value.render(captchaEl.value, {
if (captcha.value.render && captchaEl.value instanceof Element && props.sitekey) {
// reCAPTCHAcaptchaEldiv.
// divrenderreCAPTCHA
const elem = document.createElement('div');
captchaEl.value.appendChild(elem);
captchaWidgetId.value = captcha.value.render(elem, {
sitekey: props.sitekey,
theme: defaultStore.state.darkMode ? 'dark' : 'light',
callback: callback,
@ -146,6 +183,23 @@ async function requestRender() {
}
}
function clearWidget() {
if (props.provider === 'mcaptcha') {
const container = document.getElementById('mcaptcha__widget-container');
if (container) {
container.innerHTML = '';
}
} else {
reset();
remove();
if (captchaEl.value) {
//
captchaEl.value.innerHTML = '';
}
}
}
function callback(response?: string) {
emit('update:modelValue', typeof response === 'string' ? response : null);
}
@ -178,7 +232,7 @@ onUnmounted(() => {
});
onBeforeUnmount(() => {
reset();
clearWidget();
});
defineExpose({