Skip to content

Commit edcafc0

Browse files
committed
Add hcaptcha
1 parent e4e965d commit edcafc0

13 files changed

+395
-206
lines changed

assets/js/ajax.ts

+20
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,24 @@ document.addEventListener("DOMContentLoaded", () => {
3131
});
3232
});
3333

34+
type PalmtreeFormInstance = {
35+
clearState: (formControls: FormControl[]) => void;
36+
};
37+
38+
const instances = new Map<HTMLFormElement, PalmtreeFormInstance>();
39+
40+
declare global {
41+
interface Window {
42+
palmtreeForm: {
43+
getInstance: (form: HTMLFormElement) => PalmtreeFormInstance | undefined;
44+
};
45+
}
46+
}
47+
48+
window.palmtreeForm = {
49+
getInstance: (form: HTMLFormElement) => instances.get(form),
50+
};
51+
3452
export const ajax = (form: HTMLFormElement, options: Partial<PalmtreeFormOptions> = {}) => {
3553
const config = { ...defaults, ...options };
3654
const submitBtn = form.querySelector<HTMLInputElement>('button[type="submit"]');
@@ -173,4 +191,6 @@ export const ajax = (form: HTMLFormElement, options: Partial<PalmtreeFormOptions
173191
submitBtn.disabled = false;
174192
}
175193
});
194+
195+
instances.set(form, { clearState });
176196
};

assets/js/bootstrap-alerts.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ type BootstrapAlertsOptions = {
77

88
const defaults: BootstrapAlertsOptions = {
99
dismissible: true,
10-
position: "beforebegin",
10+
position: "afterbegin",
1111
};
1212

1313
export function useBootstrapAlerts(element: HTMLElement) {

assets/js/recaptcha.ts

+60-31
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,74 @@
1+
type RecaptchaApi = {
2+
render: (elementId: string, options: Record<string, unknown>) => number;
3+
reset: (widgetId: number) => void;
4+
};
5+
6+
type Config = {
7+
siteKey: string;
8+
scriptSrc: string;
9+
formControlId: string;
10+
type: "grecaptcha" | "hcaptcha";
11+
onLoadCallbackName: string;
12+
};
13+
114
interface Window {
215
[key: string]: any;
316

4-
grecaptcha: {
5-
render: (elementId: string, options: Record<string, unknown>) => number;
6-
reset: (widgetId: number) => void;
7-
};
17+
grecaptcha: RecaptchaApi;
18+
hcaptcha: RecaptchaApi;
819
}
920

1021
document.addEventListener("DOMContentLoaded", () => {
1122
document.querySelectorAll<HTMLFormElement>(".palmtree-form").forEach((form) => {
12-
const element = form.querySelector<HTMLElement>(".g-recaptcha-autoload");
13-
14-
if (element && element.dataset.onload && element.dataset.script_url) {
15-
window[element.dataset.onload] = () => {
16-
const widgetId = window.grecaptcha.render(element.id, {
17-
sitekey: element.dataset.site_key,
18-
callback: (response: string) => {
19-
const formControl = document.querySelector<HTMLInputElement>(`#${element.dataset.form_control}`);
20-
if (formControl) {
21-
formControl.value = response;
22-
23-
if (form.palmtreeForm("isInitialized")) {
24-
form.palmtreeForm("clearState", formControl);
25-
}
23+
const element = form.querySelector<HTMLElement>(".palmtree-captcha-autoload");
24+
25+
if (!element) {
26+
return;
27+
}
28+
29+
const config = JSON.parse(element.dataset.palmtreeFormCaptcha || "") as Config;
30+
31+
if (!config) {
32+
console.error("Invalid configuration");
33+
return;
34+
}
35+
36+
if (config.type !== "grecaptcha" && config.type !== "hcaptcha") {
37+
console.error(`Captcha type ${config.type} is not supported.`);
38+
return;
39+
}
40+
41+
window[config.onLoadCallbackName] = () => {
42+
const api = window[config.type];
43+
44+
const widgetId = api.render(element.id, {
45+
sitekey: config.siteKey,
46+
callback: (response: string) => {
47+
const formControl = document.querySelector<HTMLInputElement>(`#${config.formControlId}`);
48+
if (formControl) {
49+
formControl.value = response;
50+
51+
const palmtreeForm = window.palmtreeForm.getInstance(form);
52+
53+
if (palmtreeForm) {
54+
palmtreeForm.clearState([formControl]);
2655
}
27-
},
28-
});
56+
}
57+
},
58+
});
2959

30-
["error", "success"].forEach((event) => {
31-
form.addEventListener(`${event}.palmtreeForm`, () => {
32-
window.grecaptcha.reset(widgetId);
33-
});
60+
["error", "success"].forEach((event) => {
61+
form.addEventListener(`palmtreeForm.${event}`, () => {
62+
api.reset(widgetId);
3463
});
35-
};
64+
});
65+
};
3666

37-
const script = document.createElement("script");
38-
script.async = true;
39-
script.defer = true;
40-
script.src = element.dataset.script_url;
67+
const script = document.createElement("script");
68+
script.async = true;
69+
script.defer = true;
70+
script.src = config.scriptSrc;
4171

42-
document.head.append(script);
43-
}
72+
document.head.append(script);
4473
});
4574
});

examples/.bootstrap.php

+2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ function send_json($data = [], $success = true)
2424
'data' => $data,
2525
]);
2626

27+
header('Content-Type: application/json');
28+
2729
echo $response;
2830
exit;
2931
}

examples/hcaptcha/index.php

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php declare(strict_types=1);
2+
3+
use Palmtree\Form\Captcha\GoogleRecaptcha;
4+
use Palmtree\Form\Captcha\HCaptcha;
5+
use Palmtree\Form\FormBuilder;
6+
use Palmtree\Form\Type\TextType;
7+
8+
require __DIR__ . '/../../vendor/autoload.php';
9+
require __DIR__ . '/../.bootstrap.php';
10+
11+
$builder = new FormBuilder([
12+
'key' => 'hcaptcha',
13+
'html_validation' => false,
14+
]);
15+
16+
$builder
17+
->add('name', TextType::class, [
18+
'label' => 'Please enter your name',
19+
])
20+
->add('hcaptcha', 'captcha', [
21+
'captcha' => new HCaptcha('6b1ef180-ed78-4948-ae66-258e0bfe4ecc', 'ES_c1935238614149509f69db166c2f970d'),
22+
]);
23+
24+
$builder->add('send_message', 'submit');
25+
26+
$form = $builder->getForm();
27+
28+
$form->handleRequest();
29+
30+
if ($form->isSubmitted() && $form->isValid()) {
31+
redirect('?success=1');
32+
}
33+
34+
$view = template('view.phtml', [
35+
'form' => $form,
36+
'success' => (!empty($_GET['success'])),
37+
]);
38+
39+
echo $view;

examples/hcaptcha/view.phtml

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8">
5+
<title>Palmtree Form - HCaptcha Example</title>
6+
<?= get_styles(); ?>
7+
</head>
8+
<body>
9+
<main>
10+
<div class="container mt-3">
11+
<h1>Palmtree Form - HCaptcha Example</h1>
12+
<?php if ($success): ?>
13+
<div class="alert alert-success">Form submitted successfully</div>
14+
<?php endif; ?>
15+
<?= $form->render(); ?>
16+
</div>
17+
</main>
18+
<?= get_scripts(); ?>
19+
<script src="/dist/palmtree-form.pkgd.js"></script>
20+
</body>
21+
</html>

examples/recaptcha/index.php

+17-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<?php declare(strict_types=1);
22

33
use Palmtree\Form\Captcha\GoogleRecaptcha;
4+
use Palmtree\Form\Form;
45
use Palmtree\Form\FormBuilder;
56
use Palmtree\Form\Type\TextType;
67

@@ -10,6 +11,7 @@
1011
$builder = new FormBuilder([
1112
'key' => 'recaptcha',
1213
'html_validation' => false,
14+
'ajax' => true,
1315
]);
1416

1517
$builder
@@ -18,14 +20,28 @@
1820
])
1921
->add('recaptcha', 'captcha', [
2022
'captcha' => new GoogleRecaptcha('6LfOO5YUAAAAALKjc8OvDLW6WdKSxRVvQuIjEuFY', '6LfOO5YUAAAAAL5zQe0aZh2bMJq5-3sh7xKwzevR'),
21-
]);
23+
])
24+
;
2225

2326
$builder->add('send_message', 'submit');
2427

2528
$form = $builder->getForm();
2629

2730
$form->handleRequest();
2831

32+
if ($form->isSubmitted() && Form::isAjaxRequest()) {
33+
if ($form->isValid()) {
34+
send_json([
35+
'message' => 'Thanks!',
36+
]);
37+
} else {
38+
send_json_error([
39+
'message' => 'Oops! Something went wrong there. Check the form for errors',
40+
'errors' => $form->getErrors(),
41+
]);
42+
}
43+
}
44+
2945
if ($form->isSubmitted() && $form->isValid()) {
3046
redirect('?success=1');
3147
}

examples/recaptcha/view.phtml

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<body>
99
<main>
1010
<div class="container mt-3">
11-
<h1>Palmtree Form - Simple Example</h1>
11+
<h1>Palmtree Form - Recaptcha Example</h1>
1212
<?php if ($success): ?>
1313
<div class="alert alert-success">Form submitted successfully</div>
1414
<?php endif; ?>

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"build": "rollup -c",
1515
"start": "rollup -c -w",
1616
"prettier:check": "prettier --check assets/",
17+
"prettier:write": "prettier --write assets/",
1718
"type-check": "tsc --noEmit"
1819
},
1920
"prettier": {

0 commit comments

Comments
 (0)