The GUI for the Captcha service is ready.
This commit is contained in:
parent
e8c8cf7d6b
commit
fc7d1bd62f
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
.env
|
||||
/node_modules
|
||||
/.fleet
|
||||
/.idea
|
||||
/.vscode
|
BIN
exmplate/images/refresh.png
Normal file
BIN
exmplate/images/refresh.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 355 B |
12
exmplate/index.html
Normal file
12
exmplate/index.html
Normal file
@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<title>Title</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="captcha-service-kor-elf" data-domain="http://captcha.localhost:9008" data-token=""></div>
|
||||
<script src="script.js" async></script>
|
||||
</body>
|
||||
</html>
|
189
exmplate/script.js
Normal file
189
exmplate/script.js
Normal file
@ -0,0 +1,189 @@
|
||||
(function (document) {
|
||||
const captchaBlocks = document.querySelectorAll('div.captcha-service-kor-elf');
|
||||
captchaBlocks.forEach(function (element) {
|
||||
const shadow = element.attachShadow({ mode: 'closed' });
|
||||
const button = document.createElement("button");
|
||||
const style = document.createElement('link');
|
||||
const domain = element.getAttribute('data-domain');
|
||||
const token = element.getAttribute('data-token');
|
||||
|
||||
let windowCaptcha = null;
|
||||
|
||||
style.rel = 'stylesheet';
|
||||
style.type = 'text/css';
|
||||
style.href = 'style.css';
|
||||
shadow.appendChild(style);
|
||||
|
||||
button.textContent = 'Я не робот!';
|
||||
button.type = 'button';
|
||||
button.classList.add('button-open-window-captcha');
|
||||
shadow.appendChild(button);
|
||||
button.addEventListener('click', function () {
|
||||
if (windowCaptcha === null) {
|
||||
windowCaptcha = createWindowCaptcha(shadow, domain, token);
|
||||
}
|
||||
windowCaptcha.style.display = 'block';
|
||||
actionGetCaptcha(windowCaptcha, domain, token, shadow);
|
||||
});
|
||||
});
|
||||
|
||||
function createWindowCaptcha (shadow, domain, token) {
|
||||
const windowCaptcha = document.createElement('div');
|
||||
windowCaptcha.classList.add('window-captcha');
|
||||
windowCaptcha.innerHTML = `<div class="window-captcha__content">
|
||||
<div class="window-captcha__content__header">Я не робот! <button type="button" class="window-captcha__reload"></button><button type="button" class="window-captcha__close">X</button></div>
|
||||
<div class="window-captcha__content__body"></div>
|
||||
</div>`;
|
||||
shadow.appendChild(windowCaptcha);
|
||||
|
||||
windowCaptcha.addEventListener('click', function (event) {
|
||||
if (event.target !== windowCaptcha) {
|
||||
return null;
|
||||
}
|
||||
actionClose(windowCaptcha);
|
||||
});
|
||||
|
||||
windowCaptcha.querySelector('button.window-captcha__close').addEventListener('click', function () {
|
||||
actionClose(windowCaptcha);
|
||||
});
|
||||
|
||||
windowCaptcha.querySelector('button.window-captcha__reload').addEventListener('click', function () {
|
||||
actionGetCaptcha(windowCaptcha, domain, token);
|
||||
});
|
||||
|
||||
return windowCaptcha;
|
||||
}
|
||||
|
||||
function actionClose(windowCaptcha)
|
||||
{
|
||||
windowCaptcha.style.display = 'none';
|
||||
}
|
||||
|
||||
function actionGetCaptcha(windowCaptcha, domain, token, shadow)
|
||||
{
|
||||
let bodyBlock = windowCaptcha.querySelector('div.window-captcha__content__body');
|
||||
if (bodyBlock.querySelectorAll('.loading').length > 0) {
|
||||
return null;
|
||||
}
|
||||
bodyBlock.innerHTML = '<div class="loading"></div>';
|
||||
fetch(domain + '/api/v1/captcha', {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
'public-token': token
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(function (data) {
|
||||
let originalWidth = data.image_body.width;
|
||||
let originalHeight = data.image_body.height;
|
||||
bodyBlock.innerHTML = `
|
||||
<form method="post">
|
||||
<div class="window-captcha__content__body__head"><img src="${ data.image_head.base64 }" width="100%"></div>
|
||||
<p>Выберите значение в том порядке, на котором на картинке выше:</p>
|
||||
<div class="window-captcha__content__body__coordinator"><img src="${ data.image_body.base64 }" width="100%" /></div>
|
||||
<input type="hidden" name="captcha_key" class="captcha_key" value="${ data.captcha_key }" />
|
||||
<button type="button" class="window-captcha__content__body__button">Я не робот!</button>
|
||||
</form>
|
||||
`;
|
||||
let blockCoordinator = bodyBlock.querySelector('div.window-captcha__content__body__coordinator');
|
||||
let blockCoordinatorImg = blockCoordinator.querySelector('img');
|
||||
blockCoordinatorImg.addEventListener('click', function (event) {
|
||||
let pointer = document.createElement('div');
|
||||
pointer.style.left = ( event.offsetX / blockCoordinatorImg.width * 100 ) + '%';
|
||||
pointer.style.top = ( event.offsetY / blockCoordinatorImg.height * 100 ) + '%';
|
||||
pointer.classList.add('pointer');
|
||||
|
||||
let coordinatorX = event.offsetX * (originalWidth / blockCoordinatorImg.width)
|
||||
let coordinatorY = event.offsetY * (originalHeight / blockCoordinatorImg.height)
|
||||
|
||||
let pointerNumber = blockCoordinator.querySelectorAll('.pointer').length + 1
|
||||
pointer.innerHTML = `
|
||||
<span class="pounter__number">${ pointerNumber }</span>
|
||||
<input type="hidden" class="x" name="pointer[][x]" value="${ Math.round(coordinatorX) }" />
|
||||
<input type="hidden" class="y" name="pointer[][y]" value="${ Math.round(coordinatorY) }" />
|
||||
`;
|
||||
|
||||
pointer.addEventListener('click', function () {
|
||||
pointer.remove();
|
||||
blockCoordinator.querySelectorAll('.pointer').forEach(function (elementPointer, pointIndex) {
|
||||
elementPointer.querySelector('span.pounter__number').textContent = pointIndex + 1;
|
||||
});
|
||||
});
|
||||
|
||||
blockCoordinator.appendChild(pointer);
|
||||
});
|
||||
|
||||
bodyBlock.querySelector('.window-captcha__content__body__button').addEventListener('click', function () {
|
||||
checkingCaptcha(bodyBlock, domain, token, shadow);
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
bodyBlock.innerHTML = `<div class="window-captcha__content__body__error">Произошла ошибка, сервис с каптчей не ответил. Попробуйте ещё раз!</div>`;
|
||||
});
|
||||
}
|
||||
|
||||
function checkingCaptcha (bodyBlock, domain, token, shadow) {
|
||||
let button = bodyBlock.querySelector('button.window-captcha__content__body__button');
|
||||
if (button.querySelectorAll('.loading').length > 0) {
|
||||
return null;
|
||||
}
|
||||
let loadingSpan = document.createElement('span');
|
||||
loadingSpan.classList.add('loading');
|
||||
button.appendChild(loadingSpan);
|
||||
|
||||
let data = {
|
||||
captcha_key: bodyBlock.querySelector('.captcha_key').value,
|
||||
verification: []
|
||||
};
|
||||
bodyBlock.querySelectorAll('.pointer').forEach(function (elementPointer) {
|
||||
data["verification"].push({
|
||||
x: elementPointer.querySelector('.x').value,
|
||||
y: elementPointer.querySelector('.y').value
|
||||
});
|
||||
});
|
||||
|
||||
fetch(domain + '/api/v1/captcha', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
'public-token': token
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(function (data) {
|
||||
if (typeof data.errors !== 'undefined') {
|
||||
let errorMessage = '';
|
||||
for (let key in data.errors) {
|
||||
errorMessage += data.errors[key] + '<br>';
|
||||
}
|
||||
setError(errorMessage, button);
|
||||
return
|
||||
}
|
||||
shadow.querySelector('button.button-open-window-captcha').remove();
|
||||
let captchaVerified = document.createElement('div');
|
||||
captchaVerified.innerHTML = `<span class="captcha-verified">Ура!!! Проверку прошли!</span><input type="hidden" name="captcha-verified" value="${ data.captcha_key }">`;
|
||||
shadow.appendChild(captchaVerified);
|
||||
shadow.querySelector('.window-captcha').remove();
|
||||
})
|
||||
.catch(error => {
|
||||
setError('Произошла ошибка!', button)
|
||||
}).finally(function () {
|
||||
loadingSpan.remove();
|
||||
});
|
||||
}
|
||||
|
||||
function setError(message, button) {
|
||||
let errorBlock = document.createElement('div');
|
||||
errorBlock.classList.add("error-message");
|
||||
errorBlock.innerHTML = message;
|
||||
button.before(errorBlock);
|
||||
|
||||
setTimeout( function () {
|
||||
errorBlock.remove();
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
})(document);
|
171
exmplate/style.css
Normal file
171
exmplate/style.css
Normal file
@ -0,0 +1,171 @@
|
||||
.captcha-verified {
|
||||
background: #1D8100;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 90px;
|
||||
padding: 10px 20px;
|
||||
color: #000;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
font-family: serif;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
.button-open-window-captcha,
|
||||
.window-captcha__content__body__button {
|
||||
background: #68AAFF;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 90px;
|
||||
padding: 10px 20px;
|
||||
cursor: pointer;
|
||||
color: #000;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
font-family: serif;
|
||||
}
|
||||
.button-open-window-captcha:hover,
|
||||
.window-captcha__content__body__button:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
.window-captcha__content__body__button {
|
||||
border-radius: 0;
|
||||
width: 100%;
|
||||
padding: 20px 0;
|
||||
border: 0;
|
||||
position: relative;
|
||||
}
|
||||
.window-captcha__content__body__button .loading {
|
||||
background: rgba(255, 255, 255, 0.48);
|
||||
}
|
||||
.window-captcha {
|
||||
background: rgba(0, 0, 0, 0.48);
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
display: none;
|
||||
}
|
||||
.window-captcha__close {
|
||||
background: #961b1b;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
padding: 15px;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
font-family: serif;
|
||||
color: #fff;
|
||||
border: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
.window-captcha__close:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
.window-captcha__content {
|
||||
background: #fff;
|
||||
border-radius: 3px;
|
||||
margin: 20px auto;
|
||||
max-width: 600px;
|
||||
box-shadow: 3px 3px 10px rgba(0, 0, 0, 0.33);
|
||||
}
|
||||
.window-captcha__content__header {
|
||||
position: relative;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
color: #000;
|
||||
font-family: serif;
|
||||
padding: 14px 40px 7px 20px;
|
||||
border-bottom: 2px solid #ccc;
|
||||
}
|
||||
.window-captcha__reload {
|
||||
background: url('images/refresh.png') center center no-repeat;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 90px;
|
||||
cursor: pointer;
|
||||
vertical-align: middle;
|
||||
margin-left: 10px;
|
||||
}
|
||||
.window-captcha__content__reload:hover {
|
||||
background-color: rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
.window-captcha__content__body {
|
||||
min-height: 400px;
|
||||
position: relative;
|
||||
}
|
||||
.window-captcha__content__body .loading {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.window-captcha__content__body .loading:before {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border: 4px #ddd solid;
|
||||
border-top: 4px #2e93e6 solid;
|
||||
border-radius: 50%;
|
||||
animation: sp-anime 0.8s infinite linear;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
content: ' ';
|
||||
}
|
||||
.window-captcha__content__body p {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
padding: 5px 20px;
|
||||
font-family: serif;
|
||||
}
|
||||
.window-captcha__content__body__coordinator {
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
.window-captcha__content__body__coordinator .pointer {
|
||||
background: #fff;
|
||||
position: absolute;
|
||||
border-radius: 90px;
|
||||
border: 1px solid #961b1b;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
margin: -15px 0 0 -15px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: bold;
|
||||
font-family: serif;
|
||||
font-size: 16px;
|
||||
}
|
||||
.window-captcha__content__body__coordinator .pointer:hover span {
|
||||
font-size: 0;
|
||||
}
|
||||
.window-captcha__content__body__coordinator .pointer:hover span:after {
|
||||
content: "X";
|
||||
font-size: 16px;
|
||||
color: #961b1b;
|
||||
}
|
||||
.window-captcha__content__body__error {
|
||||
border: 1px solid #961b1b;
|
||||
color: #961b1b;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
margin: 20px;
|
||||
padding: 20px;
|
||||
}
|
||||
.window-captcha__content__body .error-message {
|
||||
color: #961b1b;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
padding: 20px;
|
||||
}
|
||||
@keyframes sp-anime {
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user