Skip to content

Commit

Permalink
Add hcaptcha
Browse files Browse the repository at this point in the history
  • Loading branch information
andyexeter committed Aug 23, 2024
1 parent e4e965d commit edcafc0
Show file tree
Hide file tree
Showing 13 changed files with 395 additions and 206 deletions.
20 changes: 20 additions & 0 deletions assets/js/ajax.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,24 @@ document.addEventListener("DOMContentLoaded", () => {
});
});

type PalmtreeFormInstance = {
clearState: (formControls: FormControl[]) => void;
};

const instances = new Map<HTMLFormElement, PalmtreeFormInstance>();

declare global {
interface Window {
palmtreeForm: {
getInstance: (form: HTMLFormElement) => PalmtreeFormInstance | undefined;
};
}
}

window.palmtreeForm = {
getInstance: (form: HTMLFormElement) => instances.get(form),
};

export const ajax = (form: HTMLFormElement, options: Partial<PalmtreeFormOptions> = {}) => {
const config = { ...defaults, ...options };
const submitBtn = form.querySelector<HTMLInputElement>('button[type="submit"]');
Expand Down Expand Up @@ -173,4 +191,6 @@ export const ajax = (form: HTMLFormElement, options: Partial<PalmtreeFormOptions
submitBtn.disabled = false;
}
});

instances.set(form, { clearState });
};
2 changes: 1 addition & 1 deletion assets/js/bootstrap-alerts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ type BootstrapAlertsOptions = {

const defaults: BootstrapAlertsOptions = {
dismissible: true,
position: "beforebegin",
position: "afterbegin",
};

export function useBootstrapAlerts(element: HTMLElement) {
Expand Down
91 changes: 60 additions & 31 deletions assets/js/recaptcha.ts
Original file line number Diff line number Diff line change
@@ -1,45 +1,74 @@
type RecaptchaApi = {
render: (elementId: string, options: Record<string, unknown>) => number;
reset: (widgetId: number) => void;
};

type Config = {
siteKey: string;
scriptSrc: string;
formControlId: string;
type: "grecaptcha" | "hcaptcha";
onLoadCallbackName: string;
};

interface Window {
[key: string]: any;

grecaptcha: {
render: (elementId: string, options: Record<string, unknown>) => number;
reset: (widgetId: number) => void;
};
grecaptcha: RecaptchaApi;
hcaptcha: RecaptchaApi;
}

document.addEventListener("DOMContentLoaded", () => {
document.querySelectorAll<HTMLFormElement>(".palmtree-form").forEach((form) => {
const element = form.querySelector<HTMLElement>(".g-recaptcha-autoload");

if (element && element.dataset.onload && element.dataset.script_url) {
window[element.dataset.onload] = () => {
const widgetId = window.grecaptcha.render(element.id, {
sitekey: element.dataset.site_key,
callback: (response: string) => {
const formControl = document.querySelector<HTMLInputElement>(`#${element.dataset.form_control}`);
if (formControl) {
formControl.value = response;

if (form.palmtreeForm("isInitialized")) {
form.palmtreeForm("clearState", formControl);
}
const element = form.querySelector<HTMLElement>(".palmtree-captcha-autoload");

if (!element) {
return;
}

const config = JSON.parse(element.dataset.palmtreeFormCaptcha || "") as Config;

if (!config) {
console.error("Invalid configuration");
return;
}

if (config.type !== "grecaptcha" && config.type !== "hcaptcha") {
console.error(`Captcha type ${config.type} is not supported.`);
return;
}

window[config.onLoadCallbackName] = () => {
const api = window[config.type];

const widgetId = api.render(element.id, {
sitekey: config.siteKey,
callback: (response: string) => {
const formControl = document.querySelector<HTMLInputElement>(`#${config.formControlId}`);
if (formControl) {
formControl.value = response;

const palmtreeForm = window.palmtreeForm.getInstance(form);

if (palmtreeForm) {
palmtreeForm.clearState([formControl]);
}
},
});
}
},
});

["error", "success"].forEach((event) => {
form.addEventListener(`${event}.palmtreeForm`, () => {
window.grecaptcha.reset(widgetId);
});
["error", "success"].forEach((event) => {
form.addEventListener(`palmtreeForm.${event}`, () => {
api.reset(widgetId);
});
};
});
};

const script = document.createElement("script");
script.async = true;
script.defer = true;
script.src = element.dataset.script_url;
const script = document.createElement("script");
script.async = true;
script.defer = true;
script.src = config.scriptSrc;

document.head.append(script);
}
document.head.append(script);
});
});
2 changes: 2 additions & 0 deletions examples/.bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ function send_json($data = [], $success = true)
'data' => $data,
]);

header('Content-Type: application/json');

echo $response;
exit;
}
Expand Down
39 changes: 39 additions & 0 deletions examples/hcaptcha/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php declare(strict_types=1);

use Palmtree\Form\Captcha\GoogleRecaptcha;
use Palmtree\Form\Captcha\HCaptcha;
use Palmtree\Form\FormBuilder;
use Palmtree\Form\Type\TextType;

require __DIR__ . '/../../vendor/autoload.php';
require __DIR__ . '/../.bootstrap.php';

$builder = new FormBuilder([
'key' => 'hcaptcha',
'html_validation' => false,
]);

$builder
->add('name', TextType::class, [
'label' => 'Please enter your name',
])
->add('hcaptcha', 'captcha', [
'captcha' => new HCaptcha('6b1ef180-ed78-4948-ae66-258e0bfe4ecc', 'ES_c1935238614149509f69db166c2f970d'),
]);

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

$form = $builder->getForm();

$form->handleRequest();

if ($form->isSubmitted() && $form->isValid()) {
redirect('?success=1');
}

$view = template('view.phtml', [
'form' => $form,
'success' => (!empty($_GET['success'])),
]);

echo $view;
21 changes: 21 additions & 0 deletions examples/hcaptcha/view.phtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Palmtree Form - HCaptcha Example</title>
<?= get_styles(); ?>
</head>
<body>
<main>
<div class="container mt-3">
<h1>Palmtree Form - HCaptcha Example</h1>
<?php if ($success): ?>
<div class="alert alert-success">Form submitted successfully</div>
<?php endif; ?>
<?= $form->render(); ?>
</div>
</main>
<?= get_scripts(); ?>
<script src="/dist/palmtree-form.pkgd.js"></script>
</body>
</html>
18 changes: 17 additions & 1 deletion examples/recaptcha/index.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php declare(strict_types=1);

use Palmtree\Form\Captcha\GoogleRecaptcha;
use Palmtree\Form\Form;
use Palmtree\Form\FormBuilder;
use Palmtree\Form\Type\TextType;

Expand All @@ -10,6 +11,7 @@
$builder = new FormBuilder([
'key' => 'recaptcha',
'html_validation' => false,
'ajax' => true,
]);

$builder
Expand All @@ -18,14 +20,28 @@
])
->add('recaptcha', 'captcha', [
'captcha' => new GoogleRecaptcha('6LfOO5YUAAAAALKjc8OvDLW6WdKSxRVvQuIjEuFY', '6LfOO5YUAAAAAL5zQe0aZh2bMJq5-3sh7xKwzevR'),
]);
])
;

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

$form = $builder->getForm();

$form->handleRequest();

if ($form->isSubmitted() && Form::isAjaxRequest()) {
if ($form->isValid()) {
send_json([
'message' => 'Thanks!',
]);
} else {
send_json_error([
'message' => 'Oops! Something went wrong there. Check the form for errors',
'errors' => $form->getErrors(),
]);
}
}

if ($form->isSubmitted() && $form->isValid()) {
redirect('?success=1');
}
Expand Down
2 changes: 1 addition & 1 deletion examples/recaptcha/view.phtml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<body>
<main>
<div class="container mt-3">
<h1>Palmtree Form - Simple Example</h1>
<h1>Palmtree Form - Recaptcha Example</h1>
<?php if ($success): ?>
<div class="alert alert-success">Form submitted successfully</div>
<?php endif; ?>
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"build": "rollup -c",
"start": "rollup -c -w",
"prettier:check": "prettier --check assets/",
"prettier:write": "prettier --write assets/",
"type-check": "tsc --noEmit"
},
"prettier": {
Expand Down
Loading

0 comments on commit edcafc0

Please sign in to comment.