2024-10-05 00:27:04 +02:00
<!-- Yes, this is a jolly good page with all styles glued in. Don't worry, the JS portion is here too. This way you don't need to check multiple files
And I get to save space? No, actually not.
-->
<!DOCTYPE html>
< html lang = "en" >
< head >
< meta charset = "UTF-8" / >
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" / >
< title > Guestbook usage example with the captcha< / title >
< style >
body {
margin: 0;
background-color: aliceblue;
font-family: Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;
font-size: 10pt;
}
#guestbookForm form {
display: table;
margin: 0;
align-items: center;
font-size: 1.2em;
justify-items: center;
}
#guestbookForm field {
display: table-row;
margin: 4pt 4pt 4pt 4pt;
padding: 4pt 4pt 4pt 4pt;
}
#guestbookForm label {
display: table-cell;
height: auto;
vertical-align: middle;
font-size: 1.2em;
text-align: right;
padding-right: 0.2em;
}
#guestbookForm input, textarea {
display: table-cell;
border: 0.2em hsl(78, 75%, 51%) outset;
box-shadow: 0px 0px 6px 1px rgba(0, 0, 0, .5);
border-radius: 0.4em;
padding: 0.5em 0.5em;
margin: 0.5em;
font-family: Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;
font-size: 1.2em;
resize: vertical;
min-height: 1.2em;
}
#guestbookForm input:focus, textarea:focus {
outline: none;
}
#guestbookForm div {
padding: 2pt;
}
#guestbookForm button {
font-size: 1.4em;
padding: 0.5em 1.5em;
margin: 2pt 3pt;
border-radius: 0.4em;
background-color: hsl(81, 75%, 51%);
}
.form-div {
margin: 5em auto;
width: fit-content;
height: fit-content;
align-self: center;
justify-self: center;
}
< / style >
< script src = "https://challenges.cloudflare.com/turnstile/v0/api.js" async defer > < / script >
< / head >
< body >
< div class = "form-div" >
< h1 > Sample guestbooky input page< / h1 >
<!-- A form should be defined with the action pointing to the backend's message endpoint, where the POST with the message will be sent. -->
< form id = "guestbookForm" action = "http://example.guestbook.com/message" method = "POST" >
< field >
< label for = "author" > Name: < / label >
< input type = "text" id = "author" placeholder = "Please add your name!" cols = "40" maxlength = "128" minlength = "1" required / >
< / field >
< field >
< label for = "author" > Message: < / label >
< textarea id = "message" placeholder = "Please add your message!" cols = "60" rows = "6" maxlength = "4096" minlength = "1" required > < / textarea >
< / field >
<!-- Cloudflare contains more data on how to further customize the captcha. The site key is also provided in the control panel. -->
<!-- Refer to https://developers.cloudflare.com/turnstile/get - started/client - side - rendering/ for more options. -->
<!-- Once the challenge is executed, the data is sent to the hidden field in the form through the setCaptchaResponse callback defined in the script below. -->
< field >
< label > < / label >
< div class = "cf-turnstile" data-sitekey = "0x00000000000000000000000" data-callback = "setCaptchaResponse" > < / div >
< input type = "hidden" id = "captchaResponse" name = "captchaResponse" / >
< / field >
< field >
< label > < / label >
< button type = "submit" value = "Submit" > Send< / button >
< / field >
< / form >
< / div >
<!-- Now, the script.
-> setCaptchaResponse(): callback from the turnstile to the hidden field
-> Event Listener: Listens to the submit event from the form, acquires the values and sends the POST request as structured JSON.
Once a response pops back we can check if it worked or not. This is rather crude just to get it working in a development setting.
Hopefully if this ever gets used it is tinkered with a bit.
-->
< script >
function setCaptchaResponse(token) {
document.getElementById("captchaResponse").value = token;
}
document
.getElementById("guestbookForm")
.addEventListener("submit", async function (e) {
e.preventDefault();
const author = document.getElementById("author").value;
const message = document.getElementById("message").value;
const captchaResponse = document.getElementById("captchaResponse").value;
const data = {
author,
message,
captchaResponse,
};
2024-10-27 21:01:32 +01:00
const dataJson = JSON.stringify(data);
2024-10-05 00:27:04 +02:00
2024-10-27 21:01:32 +01:00
const xhr = new XMLHttpRequest();
xhr.open("POST", this.action, true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.setRequestHeader('Content-Length', dataJson.length);
xhr.send(dataJson);
xhr.onload = function () {
if (xhr.status >= 200 & & xhr.status < = 299) {
alert("Message sent successfully.");
this.reset(); // Clear the form fields
} else {
alert("An error " + xhr.status + "occurred: " + xhr.responseText);
}
2024-10-05 00:27:04 +02:00
}
2024-10-27 21:01:32 +01:00
});
2024-10-05 00:27:04 +02:00
< / script >
< / body >
< / html >