diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..776d9dc
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,7 @@
+npm-debug.log
+yarn-error.log
+.env
+/node_modules
+/.fleet
+/.idea
+/.vscode
diff --git a/exmplate/images/refresh.png b/exmplate/images/refresh.png
new file mode 100644
index 0000000..a8eb150
Binary files /dev/null and b/exmplate/images/refresh.png differ
diff --git a/exmplate/index.html b/exmplate/index.html
new file mode 100644
index 0000000..b1ca1fa
--- /dev/null
+++ b/exmplate/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ Title
+
+
+
+
+
+
\ No newline at end of file
diff --git a/exmplate/script.js b/exmplate/script.js
new file mode 100644
index 0000000..67c7f88
--- /dev/null
+++ b/exmplate/script.js
@@ -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 = ``;
+ 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 = '';
+ 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 = `
+
+ `;
+ 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 = `
+ ${ pointerNumber }
+
+
+ `;
+
+ 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 = `Произошла ошибка, сервис с каптчей не ответил. Попробуйте ещё раз!
`;
+ });
+ }
+
+ 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] + '
';
+ }
+ setError(errorMessage, button);
+ return
+ }
+ shadow.querySelector('button.button-open-window-captcha').remove();
+ let captchaVerified = document.createElement('div');
+ captchaVerified.innerHTML = `Ура!!! Проверку прошли!`;
+ 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);
\ No newline at end of file
diff --git a/exmplate/style.css b/exmplate/style.css
new file mode 100644
index 0000000..d2328e5
--- /dev/null
+++ b/exmplate/style.css
@@ -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);
+ }
+}
\ No newline at end of file